fix: heal migration-ledger mismatch and make Azure SSO deploy-proof (#18)
PocketBase on Labs crash-looped since the SSO deploy (PR #17): mounting --migrationsDir for the first time replayed the entire migration history against a database that was provisioned out-of-band (empty _migrations ledger) and died on 1778948471_created_content.js. On top of that the team_members->auth migration had its own crash paths and trapped OAuth2 config inside a one-shot, env-dependent migration. - pb_migrations/1000000000_baseline_ledger_sync.js: detects an out-of-band provisioned DB (schema exists, ledger empty) and marks the 79 historical migrations as applied; no-op on fresh or already-synced DBs - pb_migrations/1781000000_team_members_to_auth.js: idempotency guard, relation->text conversion WITH data preservation (PocketBase diffs fields by id, so the column is backed up and restored via SQL), unique index rebuild, no silent catches, env only as fast-path - pb_hooks/entra_oidc.pb.js + pb_hooks/utils.js: reconcile the Entra OIDC provider from ENTRA_* env on every bootstrap + cron tick (compare-before-save, warn-once); heals environments that migrated without secrets and supports secret rotation without re-apply - pb_hooks/team_members.pb.js: require() pattern — JSVM runs callbacks as isolated programs, top-level helpers are not in scope (adopts Leroy's fix from the fix-sso branch) - infra/*/site/deploy-playbook.yml: health-gate after compose up — the deploy fails loudly with container logs when PocketBase does not become healthy (runs #83-#88 were green while PB crash-looped) - docker-compose.yml: .env.local is optional again - docs/auth-spec.md + AI_AGENT.md: ledger/reconciler documentation, ADRs 006-008, never-rename-applied-migrations warning Verified locally against PocketBase v0.30.4 with a 7-scenario DoD matrix (fresh DB +/- env, out-of-band DB with data incl. data preservation, populated-ledger upgrade, late-secrets healing, re-run guard, hook provisioning): 15/15 pass. npm test 112/112. Closes #18 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
34
pb_hooks/entra_oidc.pb.js
Normal file
34
pb_hooks/entra_oidc.pb.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/// <reference path="../pb_data/types.d.ts" />
|
||||
//
|
||||
// Issue #18 — Reconcile the Entra (Azure) OIDC provider from the environment.
|
||||
//
|
||||
// The team_members→auth migration (pb_migrations/1781000000) is structure-only
|
||||
// and runs exactly once. Provider CONFIGURATION lives here instead, so that:
|
||||
//
|
||||
// * an environment whose migration applied while the ENTRA_* secrets were
|
||||
// absent gets its provider enabled on the next startup (no re-apply),
|
||||
// * rotating ENTRA_CLIENT_SECRET / changing the tenant only requires new env
|
||||
// values and a container restart,
|
||||
// * a fresh database gets its provider on the first cron tick right after
|
||||
// the migrations created the collection (onBootstrap fires BEFORE the
|
||||
// migrations run — there is no post-migration lifecycle hook in the JSVM,
|
||||
// hence the cron fallback).
|
||||
//
|
||||
// The reconciler compares before saving, so both hooks are cheap no-ops when
|
||||
// everything is already in sync.
|
||||
|
||||
onBootstrap((e) => {
|
||||
e.next();
|
||||
const { reconcileEntraOidc } = require(`${__hooks}/utils.js`);
|
||||
// reconcileEntraOidc logs a warn-once itself when the ENTRA_* env is absent.
|
||||
console.log("entra_oidc reconcile (bootstrap): " + reconcileEntraOidc(e.app));
|
||||
});
|
||||
|
||||
cronAdd("entraOidcReconcile", "* * * * *", () => {
|
||||
const { reconcileEntraOidc } = require(`${__hooks}/utils.js`);
|
||||
const result = reconcileEntraOidc($app);
|
||||
// Only log state changes — this tick runs every minute.
|
||||
if (result === "updated") {
|
||||
console.log("entra_oidc reconcile (cron): OIDC provider (re)configured from ENTRA_* env");
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user