Repository navigation
Conversation
Every change to the policy keys is now a numbered version in policy_versions, whether it comes from a publish, a rollback, a whole-config PATCH (config_patch) or the first boot (bootstrap). A single draft can be saved, dry-run against recent sign-ins and published atomically. Publish and rollback need admin:write and a fresh step-up, and answer 409 when expectedVersion is stale. The dry run reports refused sign-ins and lockouts per account, caps at 10,000 accounts, and counts BREAK_GLASS_EMAILS accounts without listing them. Closes #402. Closes #403.
This was referenced Oct 22, 2026
# Conflicts: # src/routes/systemConfig.routes.ts
# Conflicts: # src/server.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #402. Closes #403.
Depends on #482 (
chore/types-0.30.0, @seamless-auth/types 0.30.0 and therecovery_codes/account_recoverykeys). This branch is stacked on it, so the diff includes that commit until #482 merges. Merge #482 first.Behaviour
login_methods,passkey_login_fallback_enabled,phishing_resistant_only,prompt_passkey_enrollment,authenticator_policy,lockout_policy,recovery_codes,account_recovery) is a numbered version inpolicy_versions:bootstrap: the first boot after upgrading records the policy in force as version 1. A later boot adds one only when env changed a policy key no admin has taken over.config_patch: a whole-configPATCH /system-config/adminthat changes a policy key, written in the PATCH's own transaction. A patch that leaves the policy unchanged records nothing.publishandrollback: the new routes.policy_drafts, constrained to a single row). It keepsbasedOnVersionacross saves.system_config(marked admin-managed), records the version and clears the draft in one transaction, then invalidates the config cache. Rollback publishes a copy of an older version as a new version withrolledBackTo. Both takeexpectedVersionand answer409 policy_version_conflictwhen stale. Version numbers are assigned under a transaction-scoped advisory lock.policy, or the draft (400 policy_candidate_requiredif neither), over the lastdays(1 to 30, default 7) of completed sign-ins, folded by attempt as the coverage report does. Registration address verification is excluded. Reasons aremethod_disabled,phishing_resistant_requiredandfallback_disabled, mirroringloginPolicyService.lockedOutusesresolveAvailableLoginMethodsplus linked identities at enabled OAuth providers.BREAK_GLASS_EMAILSaccounts are counted inbreakGlassAccountsand never evaluated or listed. The query is driven by the(type, created_at)index and capped at 10,000 accounts; a capped run is flagged in its audit event and logged.policy_draft_saved,policy_draft_discarded,policy_published,policy_rolled_back,policy_dry_run(categorysystem).Routes (contract change)
GET /system-config/policyPolicyStateResponsePUT /system-config/policy/draftPolicyDraftDELETE /system-config/policy/draftPOST /system-config/policy/publishPolicyVersion, 404 no draft, 409 stalePOST /system-config/policy/rollbackPolicyVersion, 404 unknown version, 409 staleGET /system-config/policy/versionsPolicyVersionsResponsePOST /system-config/policy/dry-runPolicyDryRunResponseAdditive only. The server adapter has no catch-all proxy, so seamless-auth-server needs passthroughs for these routes before the dashboard (seamless-auth-admin-dashboard#295) can use them.
openapi.json,adapter-manifest.jsonandsrc/generated/api.tsare regenerated.Migration verification
Run against a scratch database
seamless_policy_versions_teston the local Postgres. The database was dropped afterwards.\dshowspolicy_versions(PKversion, JSONBpolicy, source and positivity checks, self FKrolled_back_to,created_by,created_at) andpolicy_drafts(idcheck= 1, FKbased_on_version, created/updated by/at).Tests
policyVersionService.spec.ts,policyDryRun.spec.ts.systemConfig/policy.spec.tscovers every route, step-up refusal, 409, 404, and PATCHconfig_patchversioning.tests/postgres/policyVersions.spec.ts):Checks
npm run typecheck: passnpm run lint: passnpx prettier --check .: all files formattednpm run build: passnpm run check:changeset-bump: no major changesetsnpm run coverage: 144 files, 2037 passed, 1 todo. All files 98.95 lines / 95.47 branches / 99.35 functions / 99.17 statements (thresholds 98/95/98/98)TEST_DB=postgres npm run test:run(scratch DB): 147 files, 2059 passed, 1 todoChangeset: minor.