@consiliency/agent-board-schema 1.3.0 → 1.5.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.
- package/bin/agent-board-schema.js +0 -0
- package/fixtures/already-applied.json +112 -0
- package/migrations/20260717000100_agent_board_board_role.sql +180 -0
- package/migrations/20260717000200_agent_board_thread_acl.sql +149 -0
- package/migrations/20260717000300_agent_board_agent_lineage.sql +54 -0
- package/migrations/20260717000400_agent_board_delegation_policies.sql +175 -0
- package/migrations/20260718000100_agent_board_send_authz_config.sql +172 -0
- package/migrations/20260718000200_agent_board_send_role_gate.sql +804 -0
- package/migrations/20260718000300_agent_board_fleet_policy_default_deny.sql +192 -0
- package/migrations/20260718000400_agent_board_grant_ceiling_wiring.sql +58 -0
- package/migrations/20260718000500_agent_board_fleet_agent_session_class.sql +24 -0
- package/migrations/20260718000600_agent_board_mint_fleet_agent_session.sql +172 -0
- package/migrations/20260718000700_agent_board_nonfleet_session_reaper.sql +35 -0
- package/migrations/20260718000800_agent_board_regrant_scoped_send.sql +24 -0
- package/migrations/20260718000900_agent_board_agents_status_revoked.sql +24 -0
- package/migrations/20260718001000_agent_board_delegation_enforcement.sql +296 -0
- package/migrations/20260718001100_agent_board_revoke_agent_subtree.sql +238 -0
- package/migrations/20260718001200_agent_board_resigning_refresh.sql +129 -0
- package/migrations/20260718001300_agent_board_identity_providers.sql +70 -0
- package/migrations/20260718001400_agent_board_enrollment_federation_audit.sql +50 -0
- package/migrations/20260718001500_agent_board_enroll_federated_identity.sql +220 -0
- package/migrations/20260719000100_agent_board_signing_challenge_pending_cap.sql +124 -0
- package/migrations/20260719000200_agent_board_signing_challenge_reaper.sql +34 -0
- package/migrations/20260719000300_agent_board_enroll_rate_cap.sql +72 -0
- package/migrations/20260719001000_agent_board_identity_providers_portal_contract.sql +38 -0
- package/migrations/20260719001100_agent_board_enroll_federated_identity_pop.sql +267 -0
- package/migrations/20260719001200_agent_board_enroll_federated_identity_raw_fingerprint.sql +296 -0
- package/migrations/20260719001300_agent_board_enroll_rate_events_reaper_rls.sql +62 -0
- package/migrations/20260723000100_agent_board_roomown_owner_seed.sql +167 -0
- package/migrations/20260723000200_agent_board_roomown_grant_role_live.sql +72 -0
- package/package.json +9 -9
- package/schema-manifest.json +256 -4
- package/src/tooling.test.mjs +46 -1
- package/tests/agent_board_agent_lineage.test.sql +73 -0
- package/tests/agent_board_agents_status_revoked.test.sql +60 -0
- package/tests/agent_board_auth_rpcs.test.sql +17 -16
- package/tests/agent_board_board_role.test.sql +129 -0
- package/tests/agent_board_bundle_endpoint_compat.test.sql +18 -6
- package/tests/agent_board_canary_signed_fleet_enforcement.test.sql +8 -8
- package/tests/agent_board_delegation_enforcement.test.sql +175 -0
- package/tests/agent_board_delegation_policies.test.sql +120 -0
- package/tests/agent_board_enroll_federated_identity.test.sql +217 -0
- package/tests/agent_board_enroll_pop_binding.test.sql +131 -0
- package/tests/agent_board_enroll_rate_cap.test.sql +53 -0
- package/tests/agent_board_enrollment_audit_content.test.sql +139 -0
- package/tests/agent_board_fleet_agent_session_class.test.sql +64 -0
- package/tests/agent_board_fleet_policy_default_deny.test.sql +149 -0
- package/tests/agent_board_fleet_registry.test.sql +2 -2
- package/tests/agent_board_identity_providers.test.sql +104 -0
- package/tests/agent_board_inbox_rpcs.test.sql +10 -10
- package/tests/agent_board_mint_fleet_agent_session.test.sql +290 -0
- package/tests/agent_board_nonfleet_session_reaper.test.sql +61 -0
- package/tests/agent_board_portal_offline_invariant.test.sql +134 -0
- package/tests/agent_board_resigning_refresh.test.sql +73 -0
- package/tests/agent_board_revoke_agent_subtree.test.sql +188 -0
- package/tests/agent_board_roomown.test.sql +233 -0
- package/tests/agent_board_schema_version.test.sql +2 -2
- package/tests/agent_board_schema_version_rpc.test.sql +1 -1
- package/tests/agent_board_scoped_send_regrant.test.sql +142 -0
- package/tests/agent_board_send_authz_config.test.sql +84 -0
- package/tests/agent_board_send_authz_matrix.test.sql +162 -0
- package/tests/agent_board_send_role_gate.test.sql +181 -0
- package/tests/agent_board_signing_challenge_pending_cap.test.sql +87 -0
- package/tests/agent_board_signing_challenge_reaper.test.sql +74 -0
- package/tests/agent_board_thread_acl.test.sql +129 -0
- package/tests/agent_board_v2_invariants.test.sql +5 -5
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
-- ROOMOWN Lane A: room creators actually OWN the room.
|
|
2
|
+
--
|
|
3
|
+
-- Before this migration create_board wrote ONLY the boards row and never seeded a
|
|
4
|
+
-- board_memberships owner row, so the creator held no membership and could not act
|
|
5
|
+
-- as owner (grant_board_role / set_board_authority_ceiling both resolve the grantor
|
|
6
|
+
-- rank from a joined/subscribed membership). This migration:
|
|
7
|
+
--
|
|
8
|
+
-- 1. create or replace create_board so that, on a GENUINE INSERT, it also seeds a
|
|
9
|
+
-- joined `owner` board_memberships row bound to the board's ACTUAL
|
|
10
|
+
-- created_by_agent_id. The pre-existing slug-collision UPDATE path is now
|
|
11
|
+
-- OWNER-ONLY: a non-owner colliding on an existing slug raises 42501 and mutates
|
|
12
|
+
-- nothing (closing a confidentiality bypass where any authenticated agent could
|
|
13
|
+
-- overwrite another board's name/visibility/metadata). The effective actor is
|
|
14
|
+
-- resolved through _resolved_actor_agent_id, so an authenticated caller can only
|
|
15
|
+
-- create/own as itself while service_role retains create-on-behalf-of.
|
|
16
|
+
--
|
|
17
|
+
-- 2. bootstrap_board_owner_memberships(): a service_role-only repair sweep that
|
|
18
|
+
-- seeds the owner membership for pre-existing owner-less boards' created_by only.
|
|
19
|
+
--
|
|
20
|
+
-- Additive; no schema_version bump (net-new owner-seed + repair, no previously-live
|
|
21
|
+
-- authenticated contract re-activated here).
|
|
22
|
+
|
|
23
|
+
-- 1. create_board: seed owner on insert; owner-only slug-collision update ----------
|
|
24
|
+
create or replace function agent_board.create_board(
|
|
25
|
+
p_created_by_agent_id uuid,
|
|
26
|
+
p_slug text,
|
|
27
|
+
p_name text,
|
|
28
|
+
p_description text default null,
|
|
29
|
+
p_metadata jsonb default '{}'::jsonb,
|
|
30
|
+
p_visibility text default 'private'
|
|
31
|
+
)
|
|
32
|
+
returns table(board_id uuid, slug text, name text, status text, visibility text, created_at timestamptz, updated_at timestamptz)
|
|
33
|
+
language plpgsql
|
|
34
|
+
security definer
|
|
35
|
+
set search_path = agent_board, public
|
|
36
|
+
as $$
|
|
37
|
+
#variable_conflict use_column
|
|
38
|
+
declare
|
|
39
|
+
v_actor uuid;
|
|
40
|
+
v_existing agent_board.boards%rowtype;
|
|
41
|
+
v_board agent_board.boards%rowtype;
|
|
42
|
+
begin
|
|
43
|
+
if nullif(trim(p_slug), '') is null or nullif(trim(p_name), '') is null then
|
|
44
|
+
raise exception 'board slug and name are required' using errcode = '22023';
|
|
45
|
+
end if;
|
|
46
|
+
if coalesce(p_visibility, 'private') not in ('private', 'invite_only', 'open', 'directory_hidden') then
|
|
47
|
+
raise exception 'invalid board visibility' using errcode = '22023';
|
|
48
|
+
end if;
|
|
49
|
+
|
|
50
|
+
-- Effective actor: service_role -> supplied arg (create-on-behalf-of);
|
|
51
|
+
-- authenticated -> current_agent_id() and rejects arg <> current (42501).
|
|
52
|
+
v_actor := agent_board._resolved_actor_agent_id(p_created_by_agent_id, 'p_created_by_agent_id');
|
|
53
|
+
|
|
54
|
+
if not exists (select 1 from agent_board.agents where id = v_actor) then
|
|
55
|
+
raise exception 'agent not found' using errcode = 'P0002';
|
|
56
|
+
end if;
|
|
57
|
+
|
|
58
|
+
select * into v_existing
|
|
59
|
+
from agent_board.boards b
|
|
60
|
+
where b.slug = trim(p_slug);
|
|
61
|
+
|
|
62
|
+
if found then
|
|
63
|
+
-- Slug-collision path is OWNER-ONLY, keyed on CURRENT authority: the actor must
|
|
64
|
+
-- hold an ACTIVE owner-role membership on the existing board — NOT merely be its
|
|
65
|
+
-- original `created_by_agent_id`. A demoted or departed original creator no longer
|
|
66
|
+
-- owns the board and must NOT be able to re-open/rename/flip-visibility it.
|
|
67
|
+
if not exists (
|
|
68
|
+
select 1 from agent_board.board_memberships m
|
|
69
|
+
where m.board_id = v_existing.id
|
|
70
|
+
and m.agent_id = v_actor
|
|
71
|
+
and m.role = 'owner'
|
|
72
|
+
and m.membership_state in ('joined', 'subscribed')
|
|
73
|
+
) then
|
|
74
|
+
raise exception 'board slug already in use' using errcode = '42501';
|
|
75
|
+
end if;
|
|
76
|
+
|
|
77
|
+
update agent_board.boards as b
|
|
78
|
+
set name = trim(p_name),
|
|
79
|
+
description = nullif(trim(p_description), ''),
|
|
80
|
+
status = 'active',
|
|
81
|
+
visibility = coalesce(p_visibility, 'private'),
|
|
82
|
+
metadata = coalesce(b.metadata, '{}'::jsonb) || coalesce(p_metadata, '{}'::jsonb),
|
|
83
|
+
updated_at = now()
|
|
84
|
+
where b.id = v_existing.id
|
|
85
|
+
returning * into v_board;
|
|
86
|
+
-- No owner re-seed: the owner was seeded at this board's original creation, and
|
|
87
|
+
-- re-promoting on every create_board would resurrect a deliberately demoted owner.
|
|
88
|
+
else
|
|
89
|
+
insert into agent_board.boards as b(slug, name, description, created_by_agent_id, visibility, metadata)
|
|
90
|
+
values (
|
|
91
|
+
trim(p_slug),
|
|
92
|
+
trim(p_name),
|
|
93
|
+
nullif(trim(p_description), ''),
|
|
94
|
+
v_actor,
|
|
95
|
+
coalesce(p_visibility, 'private'),
|
|
96
|
+
coalesce(p_metadata, '{}'::jsonb)
|
|
97
|
+
)
|
|
98
|
+
returning * into v_board;
|
|
99
|
+
|
|
100
|
+
-- Seed the creator's owner membership, bound to the board's ACTUAL
|
|
101
|
+
-- created_by_agent_id (never the raw param). Idempotent against the active
|
|
102
|
+
-- partial-unique index so at most one active owner row exists.
|
|
103
|
+
insert into agent_board.board_memberships as bm(board_id, agent_id, membership_state, role, created_by_agent_id)
|
|
104
|
+
values (v_board.id, v_board.created_by_agent_id, 'joined', 'owner', v_board.created_by_agent_id)
|
|
105
|
+
on conflict (board_id, agent_id) where (membership_state in ('joined', 'subscribed'))
|
|
106
|
+
do update set role = 'owner', updated_at = now();
|
|
107
|
+
end if;
|
|
108
|
+
|
|
109
|
+
return query
|
|
110
|
+
select v_board.id, v_board.slug, v_board.name, v_board.status, v_board.visibility, v_board.created_at, v_board.updated_at;
|
|
111
|
+
end;
|
|
112
|
+
$$;
|
|
113
|
+
|
|
114
|
+
comment on function agent_board.create_board(uuid, text, text, text, jsonb, text) is
|
|
115
|
+
'Creates a board and, on genuine insert, seeds the creator''s joined owner membership (bound to the board''s created_by_agent_id). The slug-collision update path is owner-only (non-owner raises 42501, mutates nothing). Effective actor resolved via _resolved_actor_agent_id.';
|
|
116
|
+
|
|
117
|
+
revoke all on function agent_board.create_board(uuid, text, text, text, jsonb, text) from public, anon;
|
|
118
|
+
grant execute on function agent_board.create_board(uuid, text, text, text, jsonb, text) to authenticated, service_role;
|
|
119
|
+
|
|
120
|
+
-- 2. bootstrap_board_owner_memberships(): service_role-only owner-seed repair -------
|
|
121
|
+
create or replace function agent_board.bootstrap_board_owner_memberships()
|
|
122
|
+
returns table(board_id uuid, owner_agent_id uuid, membership_id uuid)
|
|
123
|
+
language plpgsql
|
|
124
|
+
security definer
|
|
125
|
+
set search_path = agent_board, public
|
|
126
|
+
as $$
|
|
127
|
+
#variable_conflict use_column
|
|
128
|
+
declare
|
|
129
|
+
v_row record;
|
|
130
|
+
v_membership_id uuid;
|
|
131
|
+
begin
|
|
132
|
+
-- service_role-only: current_agent_id() is null for service_role, non-null for any
|
|
133
|
+
-- authenticated principal (guarded here in addition to the EXECUTE revoke below).
|
|
134
|
+
if not agent_board._is_service_role() then
|
|
135
|
+
raise exception 'bootstrap_board_owner_memberships is service_role-only' using errcode = '42501';
|
|
136
|
+
end if;
|
|
137
|
+
|
|
138
|
+
for v_row in
|
|
139
|
+
select b.id as board_id, b.created_by_agent_id as owner_agent_id
|
|
140
|
+
from agent_board.boards b
|
|
141
|
+
where not exists (
|
|
142
|
+
select 1
|
|
143
|
+
from agent_board.board_memberships bm
|
|
144
|
+
where bm.board_id = b.id
|
|
145
|
+
and bm.agent_id = b.created_by_agent_id
|
|
146
|
+
and bm.membership_state in ('joined', 'subscribed')
|
|
147
|
+
)
|
|
148
|
+
loop
|
|
149
|
+
insert into agent_board.board_memberships as bm(board_id, agent_id, membership_state, role, created_by_agent_id)
|
|
150
|
+
values (v_row.board_id, v_row.owner_agent_id, 'joined', 'owner', v_row.owner_agent_id)
|
|
151
|
+
on conflict (board_id, agent_id) where (membership_state in ('joined', 'subscribed'))
|
|
152
|
+
do update set role = 'owner', updated_at = now()
|
|
153
|
+
returning bm.id into v_membership_id;
|
|
154
|
+
|
|
155
|
+
board_id := v_row.board_id;
|
|
156
|
+
owner_agent_id := v_row.owner_agent_id;
|
|
157
|
+
membership_id := v_membership_id;
|
|
158
|
+
return next;
|
|
159
|
+
end loop;
|
|
160
|
+
end;
|
|
161
|
+
$$;
|
|
162
|
+
|
|
163
|
+
comment on function agent_board.bootstrap_board_owner_memberships() is
|
|
164
|
+
'service_role-only repair sweep: seeds a joined owner membership for pre-existing owner-less boards, bound to each board''s created_by_agent_id. Takes no caller/role param.';
|
|
165
|
+
|
|
166
|
+
revoke all on function agent_board.bootstrap_board_owner_memberships() from public, anon, authenticated;
|
|
167
|
+
grant execute on function agent_board.bootstrap_board_owner_memberships() to service_role;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
-- ROOMOWN Lane B: activate the dormant grant_board_role chokepoint for authenticated
|
|
2
|
+
-- board owners/admins, with a privilege-escalation-safe grantor binding.
|
|
3
|
+
--
|
|
4
|
+
-- 20260718000400 shipped grant_board_role dormant (revoked from authenticated,
|
|
5
|
+
-- granted service_role) and TRUSTED p_grantor_agent_id. Now that create_board seeds
|
|
6
|
+
-- the creator's owner membership (ROOMOWN Lane A), the owner can drive grants from
|
|
7
|
+
-- their own authenticated session. Activating it safely requires binding the grantor
|
|
8
|
+
-- to the RESOLVED actor, NOT coalesce(current_agent_id(), p_grantor_agent_id):
|
|
9
|
+
-- current_agent_id() returns null for ANY authenticated caller whose agent is
|
|
10
|
+
-- suspended/credential-rotating/unmapped (20260710000000:15 filters status='active'),
|
|
11
|
+
-- and such a caller still carries a valid `authenticated` token. A coalesce would then
|
|
12
|
+
-- honor an attacker-supplied p_grantor_agent_id (owner IDs are non-secret) and let them
|
|
13
|
+
-- self-escalate. _resolved_actor_agent_id fails closed: service_role -> supplied arg;
|
|
14
|
+
-- authenticated -> current_agent_id() and raises 42501 if null or if arg <> current.
|
|
15
|
+
--
|
|
16
|
+
-- Additive; no schema_version bump. grant_board_role was never authenticated, so no
|
|
17
|
+
-- old client keys on it — this is a net-new capability, not a re-activation.
|
|
18
|
+
|
|
19
|
+
create or replace function agent_board.grant_board_role(
|
|
20
|
+
p_board_id uuid,
|
|
21
|
+
p_agent_id uuid,
|
|
22
|
+
p_grantee_role text,
|
|
23
|
+
p_grantor_agent_id uuid default null
|
|
24
|
+
)
|
|
25
|
+
returns table(board_id uuid, agent_id uuid, role text, updated_at timestamptz)
|
|
26
|
+
language plpgsql
|
|
27
|
+
security definer
|
|
28
|
+
set search_path = agent_board, public
|
|
29
|
+
as $$
|
|
30
|
+
declare
|
|
31
|
+
v_grantor uuid;
|
|
32
|
+
v_updated agent_board.board_memberships%rowtype;
|
|
33
|
+
begin
|
|
34
|
+
if p_grantee_role not in ('owner', 'admin', 'member', 'observer') then
|
|
35
|
+
raise exception 'invalid grantee role' using errcode = '22023';
|
|
36
|
+
end if;
|
|
37
|
+
|
|
38
|
+
-- Grantor is the RESOLVED actor. service_role -> supplied arg; authenticated ->
|
|
39
|
+
-- current_agent_id() and raises 42501 if null (suspended/unmapped) or if the
|
|
40
|
+
-- supplied arg <> current_agent_id(). This closes the single-principal escalation.
|
|
41
|
+
v_grantor := agent_board._resolved_actor_agent_id(p_grantor_agent_id, 'p_grantor_agent_id');
|
|
42
|
+
|
|
43
|
+
if not exists (
|
|
44
|
+
select 1 from agent_board.board_memberships bm
|
|
45
|
+
where bm.board_id = p_board_id and bm.agent_id = p_agent_id
|
|
46
|
+
) then
|
|
47
|
+
raise exception 'grantee has no membership on this board' using errcode = 'P0002';
|
|
48
|
+
end if;
|
|
49
|
+
|
|
50
|
+
-- Ceiling consumption: grantee-bounded against min(grantor role, board ceiling).
|
|
51
|
+
if not agent_board._grant_within_ceiling(v_grantor, p_board_id, p_grantee_role) then
|
|
52
|
+
raise exception 'grant exceeds grantor role or board authority ceiling' using errcode = '42501';
|
|
53
|
+
end if;
|
|
54
|
+
|
|
55
|
+
update agent_board.board_memberships bm
|
|
56
|
+
set role = p_grantee_role,
|
|
57
|
+
updated_at = now()
|
|
58
|
+
where bm.board_id = p_board_id
|
|
59
|
+
and bm.agent_id = p_agent_id
|
|
60
|
+
returning * into v_updated;
|
|
61
|
+
|
|
62
|
+
return query
|
|
63
|
+
select v_updated.board_id, v_updated.agent_id, v_updated.role, v_updated.updated_at;
|
|
64
|
+
end;
|
|
65
|
+
$$;
|
|
66
|
+
|
|
67
|
+
comment on function agent_board.grant_board_role(uuid, uuid, text, uuid) is
|
|
68
|
+
'Live board-role grant chokepoint. Grantor is the resolved actor (_resolved_actor_agent_id: service_role uses the supplied arg, authenticated uses current_agent_id() and fails closed on null/mismatch). Requires grantee membership (P0002), then enforces _grant_within_ceiling(grantor, board, grantee_role) before setting board_memberships.role.';
|
|
69
|
+
|
|
70
|
+
-- Live: authenticated owners/admins may grant (within ceiling); service_role retained.
|
|
71
|
+
revoke all on function agent_board.grant_board_role(uuid, uuid, text, uuid) from public, anon;
|
|
72
|
+
grant execute on function agent_board.grant_board_role(uuid, uuid, text, uuid) to authenticated, service_role;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@consiliency/agent-board-schema",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Canonical, immutable, exact-pinnable agent_board schema bundle: ordered SQL migrations, digest + compatibility manifest, and deterministic materialize/plan/check tooling for adopters.",
|
|
5
5
|
"repository": "https://github.com/Consiliency/message-board.git",
|
|
6
6
|
"type": "module",
|
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
"LICENSE",
|
|
26
26
|
"NOTICE"
|
|
27
27
|
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build:manifest": "node ../../scripts/build-schema-manifest.mjs",
|
|
30
|
+
"check:manifest": "node ../../scripts/build-schema-manifest.mjs --check",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"pack:smoke": "node ../../scripts/schema-packed-consumer-smoke.mjs"
|
|
33
|
+
},
|
|
28
34
|
"publishConfig": {
|
|
29
35
|
"access": "public",
|
|
30
36
|
"registry": "https://registry.npmjs.org"
|
|
@@ -32,11 +38,5 @@
|
|
|
32
38
|
"engines": {
|
|
33
39
|
"node": ">=18"
|
|
34
40
|
},
|
|
35
|
-
"license": "Apache-2.0"
|
|
36
|
-
|
|
37
|
-
"build:manifest": "node ../../scripts/build-schema-manifest.mjs",
|
|
38
|
-
"check:manifest": "node ../../scripts/build-schema-manifest.mjs --check",
|
|
39
|
-
"test": "vitest run",
|
|
40
|
-
"pack:smoke": "node ../../scripts/schema-packed-consumer-smoke.mjs"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
41
|
+
"license": "Apache-2.0"
|
|
42
|
+
}
|
package/schema-manifest.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"schema": "agent_board_schema_manifest.v1",
|
|
3
3
|
"interface": "IF-0-MBPLANE-BUNDLE-1",
|
|
4
4
|
"package": "@consiliency/agent-board-schema",
|
|
5
|
-
"packageVersion": "1.
|
|
6
|
-
"schemaVersion":
|
|
5
|
+
"packageVersion": "1.5.0",
|
|
6
|
+
"schemaVersion": 8,
|
|
7
7
|
"minClientVersion": "1.1.0",
|
|
8
8
|
"source": {
|
|
9
9
|
"portalBaseline": "94f9c269a358a943498454003e8f05f47e27a491",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"usage": "upsert (retention/monitoring defaults; on conflict do nothing)"
|
|
47
47
|
}
|
|
48
48
|
],
|
|
49
|
-
"migrationCount":
|
|
50
|
-
"aggregateSha256": "
|
|
49
|
+
"migrationCount": 73,
|
|
50
|
+
"aggregateSha256": "a43737edf382d8aee59069d6a9aec9e39fce17b31f092a3d7fcd96303b6f70e9",
|
|
51
51
|
"migrations": [
|
|
52
52
|
{
|
|
53
53
|
"order": 0,
|
|
@@ -453,6 +453,258 @@
|
|
|
453
453
|
"sourceRef": "message-board",
|
|
454
454
|
"bytes": 2159,
|
|
455
455
|
"sha256": "37a6f94d47b0948b1d5f384e52101eb48d9a15ba96a351669c87b907cc8a03e1"
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"order": 45,
|
|
459
|
+
"id": "20260717000100_agent_board_board_role",
|
|
460
|
+
"filename": "20260717000100_agent_board_board_role.sql",
|
|
461
|
+
"origin": "message-board-forward",
|
|
462
|
+
"sourceRef": "message-board",
|
|
463
|
+
"bytes": 7246,
|
|
464
|
+
"sha256": "969980a7b52c6fee9329d2367006e5ce6d36b6471b53fee2247e493ac8ae512f"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"order": 46,
|
|
468
|
+
"id": "20260717000200_agent_board_thread_acl",
|
|
469
|
+
"filename": "20260717000200_agent_board_thread_acl.sql",
|
|
470
|
+
"origin": "message-board-forward",
|
|
471
|
+
"sourceRef": "message-board",
|
|
472
|
+
"bytes": 6326,
|
|
473
|
+
"sha256": "afb323d6f9189f1f37a7fee3ffceaaa17474059d46a1fdd84adb73c28bfb27ba"
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"order": 47,
|
|
477
|
+
"id": "20260717000300_agent_board_agent_lineage",
|
|
478
|
+
"filename": "20260717000300_agent_board_agent_lineage.sql",
|
|
479
|
+
"origin": "message-board-forward",
|
|
480
|
+
"sourceRef": "message-board",
|
|
481
|
+
"bytes": 2094,
|
|
482
|
+
"sha256": "48aff20015f74e5f201a2985f71b33cd3e718aeb9dfb25fbd5720cb824fe85b3"
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"order": 48,
|
|
486
|
+
"id": "20260717000400_agent_board_delegation_policies",
|
|
487
|
+
"filename": "20260717000400_agent_board_delegation_policies.sql",
|
|
488
|
+
"origin": "message-board-forward",
|
|
489
|
+
"sourceRef": "message-board",
|
|
490
|
+
"bytes": 7551,
|
|
491
|
+
"sha256": "ef7827af400e8a6206c17c8cc35623c280a92d25f4b678314847ff308d9d9dc7"
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"order": 49,
|
|
495
|
+
"id": "20260718000100_agent_board_send_authz_config",
|
|
496
|
+
"filename": "20260718000100_agent_board_send_authz_config.sql",
|
|
497
|
+
"origin": "message-board-forward",
|
|
498
|
+
"sourceRef": "message-board",
|
|
499
|
+
"bytes": 7775,
|
|
500
|
+
"sha256": "d56909d4fbb7054e74818903d3eea84451d561c60908026dbbdb1956f500565d"
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"order": 50,
|
|
504
|
+
"id": "20260718000200_agent_board_send_role_gate",
|
|
505
|
+
"filename": "20260718000200_agent_board_send_role_gate.sql",
|
|
506
|
+
"origin": "message-board-forward",
|
|
507
|
+
"sourceRef": "message-board",
|
|
508
|
+
"bytes": 26707,
|
|
509
|
+
"sha256": "805afdef2c11e52966bec1cd47a55dfd5e687af9181316d9ef71975b516de288"
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
"order": 51,
|
|
513
|
+
"id": "20260718000300_agent_board_fleet_policy_default_deny",
|
|
514
|
+
"filename": "20260718000300_agent_board_fleet_policy_default_deny.sql",
|
|
515
|
+
"origin": "message-board-forward",
|
|
516
|
+
"sourceRef": "message-board",
|
|
517
|
+
"bytes": 9060,
|
|
518
|
+
"sha256": "47ad42dd50fb31ede0cb6044a22cce04a31168af2dead73ed8e01dabf84fddea"
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
"order": 52,
|
|
522
|
+
"id": "20260718000400_agent_board_grant_ceiling_wiring",
|
|
523
|
+
"filename": "20260718000400_agent_board_grant_ceiling_wiring.sql",
|
|
524
|
+
"origin": "message-board-forward",
|
|
525
|
+
"sourceRef": "message-board",
|
|
526
|
+
"bytes": 2626,
|
|
527
|
+
"sha256": "0461f6d403fb1dd07e9423db898cd41a15a3ecfbf75402cd0085791d57a646b7"
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
"order": 53,
|
|
531
|
+
"id": "20260718000500_agent_board_fleet_agent_session_class",
|
|
532
|
+
"filename": "20260718000500_agent_board_fleet_agent_session_class.sql",
|
|
533
|
+
"origin": "message-board-forward",
|
|
534
|
+
"sourceRef": "message-board",
|
|
535
|
+
"bytes": 1341,
|
|
536
|
+
"sha256": "028f931aaba673fba29dd92ef3c17efcc08cb50b0dab01789986652a54fb003a"
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
"order": 54,
|
|
540
|
+
"id": "20260718000600_agent_board_mint_fleet_agent_session",
|
|
541
|
+
"filename": "20260718000600_agent_board_mint_fleet_agent_session.sql",
|
|
542
|
+
"origin": "message-board-forward",
|
|
543
|
+
"sourceRef": "message-board",
|
|
544
|
+
"bytes": 7945,
|
|
545
|
+
"sha256": "25972553fd1ec4f350e751495d79695a8b0ccc66c0b8b272fdf517115ba37307"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"order": 55,
|
|
549
|
+
"id": "20260718000700_agent_board_nonfleet_session_reaper",
|
|
550
|
+
"filename": "20260718000700_agent_board_nonfleet_session_reaper.sql",
|
|
551
|
+
"origin": "message-board-forward",
|
|
552
|
+
"sourceRef": "message-board",
|
|
553
|
+
"bytes": 1490,
|
|
554
|
+
"sha256": "9b6ff596ac386c49530c9405535b5255dcb09c271288957711a0d553446ef161"
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
"order": 56,
|
|
558
|
+
"id": "20260718000800_agent_board_regrant_scoped_send",
|
|
559
|
+
"filename": "20260718000800_agent_board_regrant_scoped_send.sql",
|
|
560
|
+
"origin": "message-board-forward",
|
|
561
|
+
"sourceRef": "message-board",
|
|
562
|
+
"bytes": 2072,
|
|
563
|
+
"sha256": "1332cf2ee23d875cf0b3d646890a0fffe0efc6d2312da4e315d5dc0abadaf74f"
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
"order": 57,
|
|
567
|
+
"id": "20260718000900_agent_board_agents_status_revoked",
|
|
568
|
+
"filename": "20260718000900_agent_board_agents_status_revoked.sql",
|
|
569
|
+
"origin": "message-board-forward",
|
|
570
|
+
"sourceRef": "message-board",
|
|
571
|
+
"bytes": 1424,
|
|
572
|
+
"sha256": "f0e9b95c286bb4b6873cdc882e30262788636886360c0100b745569d6553a51b"
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
"order": 58,
|
|
576
|
+
"id": "20260718001000_agent_board_delegation_enforcement",
|
|
577
|
+
"filename": "20260718001000_agent_board_delegation_enforcement.sql",
|
|
578
|
+
"origin": "message-board-forward",
|
|
579
|
+
"sourceRef": "message-board",
|
|
580
|
+
"bytes": 14005,
|
|
581
|
+
"sha256": "7e93bd1ff924b06922bb9312684f57ce81c3d3e921dbf52357ae5059a01dbc8b"
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
"order": 59,
|
|
585
|
+
"id": "20260718001100_agent_board_revoke_agent_subtree",
|
|
586
|
+
"filename": "20260718001100_agent_board_revoke_agent_subtree.sql",
|
|
587
|
+
"origin": "message-board-forward",
|
|
588
|
+
"sourceRef": "message-board",
|
|
589
|
+
"bytes": 9849,
|
|
590
|
+
"sha256": "bcf14370a3da288ebe43e337d050f5fb6fb736fad69c9f6b7a0b6e0992371b7e"
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
"order": 60,
|
|
594
|
+
"id": "20260718001200_agent_board_resigning_refresh",
|
|
595
|
+
"filename": "20260718001200_agent_board_resigning_refresh.sql",
|
|
596
|
+
"origin": "message-board-forward",
|
|
597
|
+
"sourceRef": "message-board",
|
|
598
|
+
"bytes": 4806,
|
|
599
|
+
"sha256": "47248250ab9bc11abdea8533d62611efba9812b913dc2dc5405612eb2fbafd12"
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"order": 61,
|
|
603
|
+
"id": "20260718001300_agent_board_identity_providers",
|
|
604
|
+
"filename": "20260718001300_agent_board_identity_providers.sql",
|
|
605
|
+
"origin": "message-board-forward",
|
|
606
|
+
"sourceRef": "message-board",
|
|
607
|
+
"bytes": 4108,
|
|
608
|
+
"sha256": "ab8169709faf7f74b27a593a7c980022ee073f0371b39c0dda18f2202c0f4eae"
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
"order": 62,
|
|
612
|
+
"id": "20260718001400_agent_board_enrollment_federation_audit",
|
|
613
|
+
"filename": "20260718001400_agent_board_enrollment_federation_audit.sql",
|
|
614
|
+
"origin": "message-board-forward",
|
|
615
|
+
"sourceRef": "message-board",
|
|
616
|
+
"bytes": 2822,
|
|
617
|
+
"sha256": "c42e5122625639155d9ff1d2511ebdec3ac379ca0660e67c159e37efb8ea24f5"
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"order": 63,
|
|
621
|
+
"id": "20260718001500_agent_board_enroll_federated_identity",
|
|
622
|
+
"filename": "20260718001500_agent_board_enroll_federated_identity.sql",
|
|
623
|
+
"origin": "message-board-forward",
|
|
624
|
+
"sourceRef": "message-board",
|
|
625
|
+
"bytes": 9490,
|
|
626
|
+
"sha256": "497d1f657d78c56744017409f5bd2ca361cd691ee1d0bab5b9a55ab3dd4b8ae7"
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"order": 64,
|
|
630
|
+
"id": "20260719000100_agent_board_signing_challenge_pending_cap",
|
|
631
|
+
"filename": "20260719000100_agent_board_signing_challenge_pending_cap.sql",
|
|
632
|
+
"origin": "message-board-forward",
|
|
633
|
+
"sourceRef": "message-board",
|
|
634
|
+
"bytes": 4280,
|
|
635
|
+
"sha256": "1e48b413d31f11b9c120480c8453c8502fdde1c3a7997dcd9e22e957a2459b0b"
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
"order": 65,
|
|
639
|
+
"id": "20260719000200_agent_board_signing_challenge_reaper",
|
|
640
|
+
"filename": "20260719000200_agent_board_signing_challenge_reaper.sql",
|
|
641
|
+
"origin": "message-board-forward",
|
|
642
|
+
"sourceRef": "message-board",
|
|
643
|
+
"bytes": 1472,
|
|
644
|
+
"sha256": "488bbf16bf526b7df7c9b3fa5b068964703aa04ba657d6e6ceaff856a9523634"
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
"order": 66,
|
|
648
|
+
"id": "20260719000300_agent_board_enroll_rate_cap",
|
|
649
|
+
"filename": "20260719000300_agent_board_enroll_rate_cap.sql",
|
|
650
|
+
"origin": "message-board-forward",
|
|
651
|
+
"sourceRef": "message-board",
|
|
652
|
+
"bytes": 3195,
|
|
653
|
+
"sha256": "402c6d8bc5d4662b10d6fe0228a2bdd30026be96a5b5a237e26e1d44a639ae1d"
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
"order": 67,
|
|
657
|
+
"id": "20260719001000_agent_board_identity_providers_portal_contract",
|
|
658
|
+
"filename": "20260719001000_agent_board_identity_providers_portal_contract.sql",
|
|
659
|
+
"origin": "message-board-forward",
|
|
660
|
+
"sourceRef": "message-board",
|
|
661
|
+
"bytes": 2263,
|
|
662
|
+
"sha256": "e0406afebf9b36f3793e04ca757a252f038b4100697598e0a2e76050193674a0"
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
"order": 68,
|
|
666
|
+
"id": "20260719001100_agent_board_enroll_federated_identity_pop",
|
|
667
|
+
"filename": "20260719001100_agent_board_enroll_federated_identity_pop.sql",
|
|
668
|
+
"origin": "message-board-forward",
|
|
669
|
+
"sourceRef": "message-board",
|
|
670
|
+
"bytes": 12153,
|
|
671
|
+
"sha256": "3d4517243a7d228fb04ea41e9dc7236c870cb5830fb2f815bfa12426eee47bd7"
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
"order": 69,
|
|
675
|
+
"id": "20260719001200_agent_board_enroll_federated_identity_raw_fingerprint",
|
|
676
|
+
"filename": "20260719001200_agent_board_enroll_federated_identity_raw_fingerprint.sql",
|
|
677
|
+
"origin": "message-board-forward",
|
|
678
|
+
"sourceRef": "message-board",
|
|
679
|
+
"bytes": 13630,
|
|
680
|
+
"sha256": "70943047b522ec23ee3d451f704c961d130a053bc210dad8759cbc9a22444454"
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
"order": 70,
|
|
684
|
+
"id": "20260719001300_agent_board_enroll_rate_events_reaper_rls",
|
|
685
|
+
"filename": "20260719001300_agent_board_enroll_rate_events_reaper_rls.sql",
|
|
686
|
+
"origin": "message-board-forward",
|
|
687
|
+
"sourceRef": "message-board",
|
|
688
|
+
"bytes": 3112,
|
|
689
|
+
"sha256": "b2f58eadc13cb227991c4d978c5460878dc3cbada43c58285b55154b89a28459"
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
"order": 71,
|
|
693
|
+
"id": "20260723000100_agent_board_roomown_owner_seed",
|
|
694
|
+
"filename": "20260723000100_agent_board_roomown_owner_seed.sql",
|
|
695
|
+
"origin": "message-board-forward",
|
|
696
|
+
"sourceRef": "message-board",
|
|
697
|
+
"bytes": 7871,
|
|
698
|
+
"sha256": "ecfaf262832b3d499102ec3a2ee1d48e043b33282287d0e987555e868c07b804"
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
"order": 72,
|
|
702
|
+
"id": "20260723000200_agent_board_roomown_grant_role_live",
|
|
703
|
+
"filename": "20260723000200_agent_board_roomown_grant_role_live.sql",
|
|
704
|
+
"origin": "message-board-forward",
|
|
705
|
+
"sourceRef": "message-board",
|
|
706
|
+
"bytes": 3716,
|
|
707
|
+
"sha256": "40c9f585af16211fe9ab1d35efca6787e49b31afc7c85f208da22b9566a65575"
|
|
456
708
|
}
|
|
457
709
|
],
|
|
458
710
|
"excludedBridge": {
|
package/src/tooling.test.mjs
CHANGED
|
@@ -34,9 +34,54 @@ describe('manifest integrity', () => {
|
|
|
34
34
|
expect(manifest.source.portalBaseline).toMatch(/^[0-9a-f]{40}$/);
|
|
35
35
|
expect(manifest.source.laneHead).toMatch(/^[0-9a-f]{40}$/);
|
|
36
36
|
expect(manifest.source.mergeBase).toMatch(/^[0-9a-f]{40}$/);
|
|
37
|
-
expect(manifest.schemaVersion).toBe(
|
|
37
|
+
expect(manifest.schemaVersion).toBe(8);
|
|
38
38
|
expect(manifest.minClientVersion).toMatch(/^\d+\.\d+\.\d+$/);
|
|
39
39
|
});
|
|
40
|
+
it('registers the four MBAUTHZ + four MBSENDAUTHZ + four MBSESSION + four MBDELEG + three MBFED + three MBHARDEN + two MBPORTALGATE + two MBPORTAL-PR32 + two ROOMOWN forward migrations (migrationCount = prior 71 + 2 = 73)', () => {
|
|
41
|
+
expect(manifest.migrationCount).toBe(manifest.migrations.length);
|
|
42
|
+
expect(manifest.migrationCount).toBe(73);
|
|
43
|
+
// MBSESSION switched enforcement on (scoped-send re-grant): the client-visible
|
|
44
|
+
// schema version bumped to 8. MBDELEG tightens delegation and MBFED adds only
|
|
45
|
+
// enrollment-only additive surface (identity_providers registry, enrollment audit,
|
|
46
|
+
// the enroll RPC, and the /enroll EF) with no client-visible write-path shape
|
|
47
|
+
// change, so the version stays 8. MBHARDEN adds three additive pre-live hardening
|
|
48
|
+
// migrations (challenge pending-cap, challenge reaper, /enroll rate cap) with no
|
|
49
|
+
// client-visible write-path shape change, so the version stays 8.
|
|
50
|
+
expect(manifest.schemaVersion).toBe(8);
|
|
51
|
+
const names = new Set(manifest.migrations.map((m) => m.filename));
|
|
52
|
+
for (const f of [
|
|
53
|
+
'20260717000100_agent_board_board_role.sql',
|
|
54
|
+
'20260717000200_agent_board_thread_acl.sql',
|
|
55
|
+
'20260717000300_agent_board_agent_lineage.sql',
|
|
56
|
+
'20260717000400_agent_board_delegation_policies.sql',
|
|
57
|
+
'20260718000100_agent_board_send_authz_config.sql',
|
|
58
|
+
'20260718000200_agent_board_send_role_gate.sql',
|
|
59
|
+
'20260718000300_agent_board_fleet_policy_default_deny.sql',
|
|
60
|
+
'20260718000400_agent_board_grant_ceiling_wiring.sql',
|
|
61
|
+
'20260718000500_agent_board_fleet_agent_session_class.sql',
|
|
62
|
+
'20260718000600_agent_board_mint_fleet_agent_session.sql',
|
|
63
|
+
'20260718000700_agent_board_nonfleet_session_reaper.sql',
|
|
64
|
+
'20260718000800_agent_board_regrant_scoped_send.sql',
|
|
65
|
+
'20260718000900_agent_board_agents_status_revoked.sql',
|
|
66
|
+
'20260718001000_agent_board_delegation_enforcement.sql',
|
|
67
|
+
'20260718001100_agent_board_revoke_agent_subtree.sql',
|
|
68
|
+
'20260718001200_agent_board_resigning_refresh.sql',
|
|
69
|
+
'20260718001300_agent_board_identity_providers.sql',
|
|
70
|
+
'20260718001400_agent_board_enrollment_federation_audit.sql',
|
|
71
|
+
'20260718001500_agent_board_enroll_federated_identity.sql',
|
|
72
|
+
'20260719000100_agent_board_signing_challenge_pending_cap.sql',
|
|
73
|
+
'20260719000200_agent_board_signing_challenge_reaper.sql',
|
|
74
|
+
'20260719000300_agent_board_enroll_rate_cap.sql',
|
|
75
|
+
'20260719001200_agent_board_enroll_federated_identity_raw_fingerprint.sql',
|
|
76
|
+
'20260719001300_agent_board_enroll_rate_events_reaper_rls.sql',
|
|
77
|
+
// ROOMOWN: room ownership + self-service authority (create_board owner-seed +
|
|
78
|
+
// bootstrap; grant_board_role activated for authenticated). schema stays 8.
|
|
79
|
+
'20260723000100_agent_board_roomown_owner_seed.sql',
|
|
80
|
+
'20260723000200_agent_board_roomown_grant_role_live.sql',
|
|
81
|
+
]) {
|
|
82
|
+
expect(names.has(f)).toBe(true);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
40
85
|
});
|
|
41
86
|
|
|
42
87
|
describe('materialize (sole adopter path)', () => {
|