2.6 KiB
Independent policy approval
Set REQUIRE_INDEPENDENT_POLICY_APPROVAL=true on the management server. This deployment control is outside signed browser policy, so neither a policy draft nor a restored version can disable it. The example deployment enables it. Absent configuration remains false for existing local development fixtures.
With the control enabled, global policy changes, teaching publication, blocklist changes, individual device document-scan changes, and historical restoration all create durable pending reviews and return HTTP 202. Nothing is signed or applied until a different authenticated administrator approves. Operators can prepare changes; auditors can inspect; only administrators can approve or reject. The same subject cannot review its own change, even if its role changes.
Each review freezes the normalized full policy, operation, expected current version and SHA-256 payload hash. Approval must present the displayed hash and expected version. Inside one SQLite write transaction the server verifies integrity, current policy version, expiry, bookmark consistency, applicable device/teaching state, then publishes a new monotonic version and applies associated effects. Changed policy versions make older drafts stale; the server never silently rebases them. Repeated approvals and changed hashes are rejected.
Review APIs:
GET /api/admin/policy-reviews: latest 100 reviews, status and deployment requirement.GET /api/admin/policy-reviews/:id: immutable candidate, operation and bounded diff against current policy.POST /api/admin/policy-reviewswith{policy}: explicit review preparation.POST /api/admin/policy-reviews/:id/approvewith{payloadHash,expectedVersion,approve:true}.POST /api/admin/policy-reviews/:id/rejectwith{payloadHash,reject:true}.
Ordinary publication endpoints return {reviewRequired:true,reviewId,status:"pending",expectedVersion,payloadHash} instead of a new published version when approval is mandatory. Review audit records contain subjects, IDs, versions and hashes, without policy values or document content. Policy/review storage itself contains sensitive policy configuration and must be protected as management data.
Tests in tests/policy-review.test.mjs cover author/role separation, hash mismatch, stale versions, rejection, repeat publication, queue integrity corruption, and every alternative publication entry point including atomic teaching and device effects. Production operation still requires separate real SSO identities and protected management access; a shared loopback development bootstrap identity cannot demonstrate independent approval.