@consiliency/agent-board-schema 1.48.0 → 1.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/fixtures/already-applied.json +16 -0
  2. package/migrations/20260929000100_agent_board_advisory_revert_cap_reset.sql +371 -0
  3. package/migrations/20260930000100_agent_board_claim_policy_race.sql +922 -0
  4. package/migrations/20261001000100_agent_board_claimpolicy_lock_grant_revoke.sql +158 -0
  5. package/migrations/20261002000100_agent_board_session_challenge_supersede.sql +383 -0
  6. package/package.json +1 -1
  7. package/schema-manifest.json +39 -3
  8. package/src/tooling.test.mjs +33 -2
  9. package/tests/agent_board_board_claim_policy.test.sql +261 -1
  10. package/tests/agent_board_claim_subject_gate.test.sql +11 -2
  11. package/tests/agent_board_claimkey.test.sql +17 -2
  12. package/tests/agent_board_claimpolicy_race.test.sql +1374 -0
  13. package/tests/agent_board_fk_lock_edges.test.sql +20 -0
  14. package/tests/agent_board_ownerless_quota_census.test.sql +6 -0
  15. package/tests/agent_board_ownerless_renew_quota.test.sql +37 -8
  16. package/tests/agent_board_signing_challenge_pending_cap.test.sql +391 -36
  17. package/tests/catalog/p_metadata_parameters.json +16 -0
  18. package/tests/fixtures/test-prereqs.sql +186 -0
  19. package/tests/isolation/expected/challenge_supersede_lock_order.out +213 -0
  20. package/tests/isolation/expected/claimpolicy_acquire_revert_race.out +66 -0
  21. package/tests/isolation/expected/claimpolicy_board_scope.out +73 -0
  22. package/tests/isolation/expected/claimpolicy_claimrow_lock_order.out +80 -0
  23. package/tests/isolation/expected/claimpolicy_isolation_refusal.out +114 -0
  24. package/tests/isolation/expected/claimpolicy_renew_revert_race.out +66 -0
  25. package/tests/isolation/expected/claimpolicy_writer_keyshare.out +49 -0
  26. package/tests/isolation/specs/challenge_supersede_lock_order.spec +183 -0
  27. package/tests/isolation/specs/claimpolicy_acquire_revert_race.spec +118 -0
  28. package/tests/isolation/specs/claimpolicy_board_scope.spec +115 -0
  29. package/tests/isolation/specs/claimpolicy_claimrow_lock_order.spec +200 -0
  30. package/tests/isolation/specs/claimpolicy_isolation_refusal.spec +162 -0
  31. package/tests/isolation/specs/claimpolicy_renew_revert_race.spec +150 -0
  32. package/tests/isolation/specs/claimpolicy_writer_keyshare.spec +107 -0
  33. package/tests/seeds/20261001000100_agent_board_claimpolicy_lock_grant_revoke.sql.pre.sql +99 -0
@@ -0,0 +1,99 @@
1
+ -- Consiliency/message-board#405 — the ADVERSARIAL PRE-STATE for 20261001000100.
2
+ --
3
+ -- WHAT THIS GATES, and why an assertion could not. CPR-22 checks the lock helper's final ACL in the
4
+ -- ordinary fixture — where there is no delegated grant — so it stays GREEN if the migration's
5
+ -- `CASCADE` were removed or its sweep narrowed back to a list of known roles. The migration's
6
+ -- claimed behaviour is about a state the fixture never contains, so the fixture has to contain it.
7
+ --
8
+ -- THE STATE: `service_role` holds EXECUTE **WITH GRANT OPTION** and has granted it onward to
9
+ -- `anon`. That is the adopter shape the migration exists to survive: a plain `REVOKE` defaults to
10
+ -- RESTRICT and fails `dependent privileges exist` against it, which on an adopter database is a
11
+ -- FAILED UPGRADE rather than a tidier ACL. Measured against this bundle: the plain form errors, the
12
+ -- shipped form exits 0 and leaves `{postgres=X/postgres}`.
13
+ --
14
+ -- HOW THE GATE READS. This runs BEFORE 20261001000100 (the runner's tests/seeds/<migration>.pre.sql
15
+ -- hook, #103). Afterwards, either
16
+ -- * the migration swept the chain and CPR-22 reports an empty ACL — the claim holds; or
17
+ -- * the migration RAISED, and the whole bundle replay fails loudly at this migration.
18
+ -- There is no third outcome in which a narrowed sweep passes quietly.
19
+ --
20
+ -- ONLY PRE-EXISTING ROLES ARE USED — no CREATE ROLE. Roles are cluster-global, so a seed that
21
+ -- created them would leak them into a shared cluster and could collide with a concurrent run;
22
+ -- service_role and anon are part of the adopter base this bundle already assumes.
23
+ --
24
+ -- WHAT THIS FIXTURE GATES, precisely — and the second clause is NARROWER than an earlier version of
25
+ -- this paragraph claimed. It gates that the sweep CASCADEs, and that it reaches a grantee OUTSIDE
26
+ -- THE HISTORICAL HAND LIST (public/anon/authenticated/service_role). It does NOT gate that the
27
+ -- sweep is catalog-DERIVED: a migration hard-coded to those four PLUS `authenticator` clears this
28
+ -- fixture and its guard below. A fixture names specific roles by construction, so only a randomly
29
+ -- generated grantee defeats any hand list.
30
+ --
31
+ -- A DISPOSABLE RANDOM GRANTEE WAS CONSIDERED AND REJECTED, checked rather than reasoned about. The
32
+ -- runner has a `.pre.sql` hook and no post hook, so a role created here is never dropped; a seed
33
+ -- that swept `mb_seed405_%` at its start to compensate would be dropping roles belonging to any
34
+ -- CONCURRENT run on the same cluster, and this cluster is shared. Trading a stated gap for
35
+ -- cross-run interference is the worse deal. Derivation itself stays mutation-verified: narrowing
36
+ -- the sweep to known roles was injected and CPR-22 named the survivor.
37
+ --
38
+ -- WHAT IT DOES NOT GATE: that the sweep derives its SIGNATURES. That needs a pre-existing overload,
39
+ -- and a seeded overload PERSISTS — the runner has a `.pre.sql` hook and no post hook, so nothing
40
+ -- drops it, and tests/catalog/p_metadata_parameters.json enumerates every agent_board signature and
41
+ -- would go red. Checked rather than assumed. So a migration narrowed back to the `(uuid)` signature
42
+ -- stays green here; that half is mutation-verified only, and this paragraph is the record of it
43
+ -- rather than a silence someone has to rediscover.
44
+
45
+ do $$
46
+ begin
47
+ -- Idempotent: a re-replay onto a database that already carries the chain must not fail here, or
48
+ -- the seed becomes a worse failure mode than the one it tests for.
49
+ if not exists (select 1 from pg_roles where rolname = 'service_role')
50
+ or not exists (select 1 from pg_roles where rolname = 'anon') then
51
+ raise exception
52
+ 'claimpolicy lock-grant seed: service_role/anon absent — the adopter base this bundle assumes is not present'
53
+ using errcode = '42704';
54
+ end if;
55
+
56
+ -- A GRANTEE OUTSIDE THE FOUR NAMES THE OLD HAND LIST USED. Without this the fixture gates only
57
+ -- "CASCADE is present": a migration hard-coded to revoke public/anon/authenticated/service_role
58
+ -- with CASCADE would sweep the chain below, pass, and still abandon every arbitrary adopter
59
+ -- grantee — which is the entire reason the sweep was made catalog-derived. `authenticator` is
60
+ -- outside that list and is part of the Supabase adopter base, so nothing has to be created:
61
+ -- a role invented here would linger cluster-wide, since a seed has no post hook to drop it.
62
+ execute 'grant execute on function agent_board._claimgate_lock_board_policy(uuid) to authenticator';
63
+
64
+ execute 'grant execute on function agent_board._claimgate_lock_board_policy(uuid) to service_role with grant option';
65
+ end $$;
66
+
67
+ -- The onward grant must be made BY service_role, so the dependency really exists.
68
+ --
69
+ -- `SET ROLE`, NOT `SET LOCAL ROLE`, and that distinction is the whole gate. The runner applies this
70
+ -- file with `psql -f` in AUTOCOMMIT, so every statement is its own implicit transaction and a
71
+ -- `SET LOCAL` is discarded before the next one runs. The first version used SET LOCAL: the grant was
72
+ -- then made by `postgres`, recorded as `anon=X/postgres` with no dependency on service_role's grant,
73
+ -- and a plain RESTRICT revoke would have swept it happily — a gate that passed whether or not the
74
+ -- migration cascaded. The check below caught exactly that, which is why it is here.
75
+ set role service_role;
76
+ grant execute on function agent_board._claimgate_lock_board_policy(uuid) to anon;
77
+ reset role;
78
+
79
+ -- Proof the pre-state is what this file claims, checked rather than assumed: if the chain did not
80
+ -- form, the migration would sweep a state no harder than the ordinary one and the gate would be
81
+ -- vacuous — green for the wrong reason, which is the failure mode this whole effort keeps finding.
82
+ do $$
83
+ declare v_acl text;
84
+ begin
85
+ select coalesce(proacl::text, '<null>') into v_acl
86
+ from pg_proc where oid = to_regprocedure('agent_board._claimgate_lock_board_policy(uuid)');
87
+ if v_acl not like '%anon=X/service_role%' then
88
+ raise exception
89
+ 'claimpolicy lock-grant seed: the delegated grant did not form (acl=%) — refusing to leave a VACUOUS gate that would pass whether or not the migration cascades',
90
+ v_acl
91
+ using errcode = '55000';
92
+ end if;
93
+ if v_acl not like '%authenticator=%' then
94
+ raise exception
95
+ 'claimpolicy lock-grant seed: the out-of-list grantee did not take (acl=%) — without it this fixture gates only CASCADE, and a migration narrowed to the four historical role names would pass',
96
+ v_acl
97
+ using errcode = '55000';
98
+ end if;
99
+ end $$;