@consiliency/agent-board-schema 1.2.0 → 1.4.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 +108 -0
- package/migrations/20260714000200_agent_board_workload_providers_rls.sql +35 -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/package.json +9 -9
- package/schema-manifest.json +247 -4
- package/src/tooling.test.mjs +42 -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 +119 -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 +134 -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 +6 -6
- 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 +130 -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_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 +138 -0
- package/tests/agent_board_send_authz_config.test.sql +84 -0
- package/tests/agent_board_send_authz_matrix.test.sql +159 -0
- package/tests/agent_board_send_role_gate.test.sql +177 -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_workload_providers_rls.test.sql +40 -0
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.4.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": 71,
|
|
50
|
+
"aggregateSha256": "794661727d22a39e2d42ddfc5d6456fb93165cef68af11fb361385c29dbdead9",
|
|
51
51
|
"migrations": [
|
|
52
52
|
{
|
|
53
53
|
"order": 0,
|
|
@@ -444,6 +444,249 @@
|
|
|
444
444
|
"sourceRef": "message-board",
|
|
445
445
|
"bytes": 3464,
|
|
446
446
|
"sha256": "ba2c55bd11600d3dc86d54f02acd48ef4de711aaedce425e6bbfc85284a46c74"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"order": 44,
|
|
450
|
+
"id": "20260714000200_agent_board_workload_providers_rls",
|
|
451
|
+
"filename": "20260714000200_agent_board_workload_providers_rls.sql",
|
|
452
|
+
"origin": "message-board-forward",
|
|
453
|
+
"sourceRef": "message-board",
|
|
454
|
+
"bytes": 2159,
|
|
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"
|
|
447
690
|
}
|
|
448
691
|
],
|
|
449
692
|
"excludedBridge": {
|
package/src/tooling.test.mjs
CHANGED
|
@@ -34,9 +34,50 @@ 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 forward migrations (migrationCount = prior 67 + 4 = 71)', () => {
|
|
41
|
+
expect(manifest.migrationCount).toBe(manifest.migrations.length);
|
|
42
|
+
expect(manifest.migrationCount).toBe(71);
|
|
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
|
+
]) {
|
|
78
|
+
expect(names.has(f)).toBe(true);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
40
81
|
});
|
|
41
82
|
|
|
42
83
|
describe('materialize (sole adopter path)', () => {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
-- MBAUTHZ SL-3 (Lane C) pgTAP: agents.parent_agent_id / root_agent_id and the
|
|
2
|
+
-- owner-consistency trigger.
|
|
3
|
+
create extension if not exists pgtap with schema extensions;
|
|
4
|
+
set search_path = extensions, public, agent_board;
|
|
5
|
+
|
|
6
|
+
begin;
|
|
7
|
+
|
|
8
|
+
select plan(8);
|
|
9
|
+
|
|
10
|
+
create temp table _lineage_fixture (
|
|
11
|
+
root_agent uuid,
|
|
12
|
+
root_user uuid,
|
|
13
|
+
other_user uuid
|
|
14
|
+
) on commit drop;
|
|
15
|
+
|
|
16
|
+
do $$
|
|
17
|
+
declare
|
|
18
|
+
v_suffix text := replace(substr(gen_random_uuid()::text, 1, 8), '-', '');
|
|
19
|
+
v_root_user uuid;
|
|
20
|
+
v_other_user uuid;
|
|
21
|
+
v_root uuid := gen_random_uuid();
|
|
22
|
+
begin
|
|
23
|
+
v_root_user := public.ensure_github_user('lin-root-' || v_suffix, 'lin-root-' || v_suffix || '@example.test', 'lin-root-' || v_suffix, 'LIN Root');
|
|
24
|
+
v_other_user := public.ensure_github_user('lin-other-' || v_suffix, 'lin-other-' || v_suffix || '@example.test', 'lin-other-' || v_suffix, 'LIN Other');
|
|
25
|
+
|
|
26
|
+
insert into agent_board.agents(id, agent_type, handle, display_name, status, auth_user_id, owner_user_id)
|
|
27
|
+
values (v_root, 'agent', 'lin-root-' || v_suffix, 'LIN Root', 'active', v_root_user, v_root_user);
|
|
28
|
+
|
|
29
|
+
insert into _lineage_fixture values (v_root, v_root_user, v_other_user);
|
|
30
|
+
end
|
|
31
|
+
$$;
|
|
32
|
+
|
|
33
|
+
-- Structure -----------------------------------------------------------------
|
|
34
|
+
select has_column('agent_board', 'agents', 'parent_agent_id', 'agents has parent_agent_id');
|
|
35
|
+
select has_column('agent_board', 'agents', 'root_agent_id', 'agents has root_agent_id');
|
|
36
|
+
select col_type_is('agent_board', 'agents', 'parent_agent_id', 'uuid', 'parent_agent_id is uuid');
|
|
37
|
+
select fk_ok('agent_board', 'agents', 'parent_agent_id', 'agent_board', 'agents', 'id',
|
|
38
|
+
'parent_agent_id references agents(id)');
|
|
39
|
+
select fk_ok('agent_board', 'agents', 'root_agent_id', 'agent_board', 'agents', 'id',
|
|
40
|
+
'root_agent_id references agents(id)');
|
|
41
|
+
|
|
42
|
+
-- Owner-consistency trigger -------------------------------------------------
|
|
43
|
+
-- Child whose owner_user_id differs from its root's owner is rejected.
|
|
44
|
+
select throws_ok(
|
|
45
|
+
(select format(
|
|
46
|
+
$q$insert into agent_board.agents(id, agent_type, handle, display_name, status, owner_user_id, parent_agent_id, root_agent_id)
|
|
47
|
+
values (gen_random_uuid(), 'agent', %L, 'LIN Bad Child', 'active', %L::uuid, %L::uuid, %L::uuid)$q$,
|
|
48
|
+
'lin-badchild-' || gen_random_uuid()::text, other_user, root_agent, root_agent)
|
|
49
|
+
from _lineage_fixture),
|
|
50
|
+
'23514', null,
|
|
51
|
+
'trigger rejects a parented agent whose owner differs from its root');
|
|
52
|
+
|
|
53
|
+
-- Child whose owner matches its root's owner is allowed.
|
|
54
|
+
select lives_ok(
|
|
55
|
+
(select format(
|
|
56
|
+
$q$insert into agent_board.agents(id, agent_type, handle, display_name, status, owner_user_id, parent_agent_id, root_agent_id)
|
|
57
|
+
values (gen_random_uuid(), 'agent', %L, 'LIN Good Child', 'active', %L::uuid, %L::uuid, %L::uuid)$q$,
|
|
58
|
+
'lin-goodchild-' || gen_random_uuid()::text, root_user, root_agent, root_agent)
|
|
59
|
+
from _lineage_fixture),
|
|
60
|
+
'trigger allows a parented agent whose owner matches its root');
|
|
61
|
+
|
|
62
|
+
-- Unparented agent (NULL lineage) is unaffected regardless of owner.
|
|
63
|
+
select lives_ok(
|
|
64
|
+
(select format(
|
|
65
|
+
$q$insert into agent_board.agents(id, agent_type, handle, display_name, status, owner_user_id)
|
|
66
|
+
values (gen_random_uuid(), 'agent', %L, 'LIN Orphan', 'active', %L::uuid)$q$,
|
|
67
|
+
'lin-orphan-' || gen_random_uuid()::text, other_user)
|
|
68
|
+
from _lineage_fixture),
|
|
69
|
+
'unparented agent with NULL lineage is unaffected by the trigger');
|
|
70
|
+
|
|
71
|
+
select finish();
|
|
72
|
+
|
|
73
|
+
rollback;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
-- MBDELEG SL-1 pgTAP (IF-0-MBDELEG-1): agents.status admits 'revoked'.
|
|
2
|
+
--
|
|
3
|
+
-- Proves the CHECK-extension at 20260718000900 accepts the 4th literal 'revoked'
|
|
4
|
+
-- alongside the 3 legacy literals, rejects an unknown literal, and that a write of
|
|
5
|
+
-- status='revoked' (as the cascade performs) no longer throws check_violation.
|
|
6
|
+
--
|
|
7
|
+
-- Runs as postgres (service_role-equivalent).
|
|
8
|
+
create extension if not exists pgtap with schema extensions;
|
|
9
|
+
set search_path = extensions, public, agent_board;
|
|
10
|
+
|
|
11
|
+
begin;
|
|
12
|
+
|
|
13
|
+
select plan(6);
|
|
14
|
+
|
|
15
|
+
create temp table _srv_fx (a_upd uuid) on commit drop;
|
|
16
|
+
|
|
17
|
+
do $$
|
|
18
|
+
declare
|
|
19
|
+
s text := replace(substr(gen_random_uuid()::text, 1, 8), '-', '');
|
|
20
|
+
v_upd uuid := gen_random_uuid();
|
|
21
|
+
begin
|
|
22
|
+
-- Seed one agent to update to 'revoked' below.
|
|
23
|
+
insert into agent_board.agents(id, agent_type, handle, display_name, status)
|
|
24
|
+
values (v_upd, 'agent', 'srv-upd-'||s, 'SRV-UPD', 'active');
|
|
25
|
+
insert into _srv_fx values (v_upd);
|
|
26
|
+
end
|
|
27
|
+
$$;
|
|
28
|
+
|
|
29
|
+
-- Insert-side acceptance of each literal (distinct handles).
|
|
30
|
+
select lives_ok(
|
|
31
|
+
$q$insert into agent_board.agents(agent_type, handle, display_name, status)
|
|
32
|
+
values ('agent', 'srv-active-'||replace(substr(gen_random_uuid()::text,1,8),'-',''), 'A', 'active')$q$,
|
|
33
|
+
'agents.status accepts legacy literal ''active''');
|
|
34
|
+
select lives_ok(
|
|
35
|
+
$q$insert into agent_board.agents(agent_type, handle, display_name, status)
|
|
36
|
+
values ('agent', 'srv-inactive-'||replace(substr(gen_random_uuid()::text,1,8),'-',''), 'I', 'inactive')$q$,
|
|
37
|
+
'agents.status accepts legacy literal ''inactive''');
|
|
38
|
+
select lives_ok(
|
|
39
|
+
$q$insert into agent_board.agents(agent_type, handle, display_name, status)
|
|
40
|
+
values ('agent', 'srv-suspended-'||replace(substr(gen_random_uuid()::text,1,8),'-',''), 'S', 'suspended')$q$,
|
|
41
|
+
'agents.status accepts legacy literal ''suspended''');
|
|
42
|
+
select lives_ok(
|
|
43
|
+
$q$insert into agent_board.agents(agent_type, handle, display_name, status)
|
|
44
|
+
values ('agent', 'srv-revoked-'||replace(substr(gen_random_uuid()::text,1,8),'-',''), 'R', 'revoked')$q$,
|
|
45
|
+
'agents.status accepts the new literal ''revoked''');
|
|
46
|
+
|
|
47
|
+
-- An unknown literal is rejected by agents_status_check.
|
|
48
|
+
select throws_ok(
|
|
49
|
+
$q$insert into agent_board.agents(agent_type, handle, display_name, status)
|
|
50
|
+
values ('agent', 'srv-bogus-'||replace(substr(gen_random_uuid()::text,1,8),'-',''), 'B', 'bogus')$q$,
|
|
51
|
+
'23514', null, 'agents.status rejects an unknown literal (check_violation)');
|
|
52
|
+
|
|
53
|
+
-- A subtree write of status='revoked' (what the cascade performs) succeeds.
|
|
54
|
+
select lives_ok(
|
|
55
|
+
(select format($q$update agent_board.agents set status = 'revoked' where id = %L::uuid$q$, a_upd) from _srv_fx),
|
|
56
|
+
'updating an existing agent to status=''revoked'' no longer throws check_violation');
|
|
57
|
+
|
|
58
|
+
select finish();
|
|
59
|
+
|
|
60
|
+
rollback;
|
|
@@ -155,13 +155,15 @@ begin
|
|
|
155
155
|
|
|
156
156
|
v_previous_credential_id := v_agent_one.credential_id;
|
|
157
157
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
raise exception 'rotate_agent_token
|
|
164
|
-
|
|
158
|
+
-- MBDELEG (20260718001200): the 30-day refresh-token exchange is retired.
|
|
159
|
+
-- rotate_agent_token now raises 0A000; session refresh is re-signing
|
|
160
|
+
-- (PoP -> mint_fleet_agent_session), not a refresh-token rotation.
|
|
161
|
+
begin
|
|
162
|
+
perform * from agent_board.rotate_agent_token(v_agent_one.agent_id);
|
|
163
|
+
raise exception 'rotate_agent_token unexpectedly succeeded (should be deprecated)';
|
|
164
|
+
exception
|
|
165
|
+
when sqlstate '0A000' then null;
|
|
166
|
+
end;
|
|
165
167
|
|
|
166
168
|
select *
|
|
167
169
|
into v_revoked
|
|
@@ -263,12 +265,11 @@ $$;
|
|
|
263
265
|
|
|
264
266
|
select pass('AUTHRPC preserved the service_role callback-runtime path');
|
|
265
267
|
|
|
266
|
-
-- portal#203 (defense in depth): rotate_agent_token
|
|
267
|
-
--
|
|
268
|
-
--
|
|
269
|
-
-- system
|
|
270
|
-
--
|
|
271
|
-
-- platform-admin gate for a service/superuser caller, so the guard is exercised.
|
|
268
|
+
-- portal#203 + MBDELEG (20260718001200, defense in depth): rotate_agent_token is
|
|
269
|
+
-- now deprecated and raises 0A000 for ALL callers (session refresh is re-signing),
|
|
270
|
+
-- which subsumes the earlier system-principal fail-closed path. A pre-existing
|
|
271
|
+
-- system principal must still get no credential from rotation. Create one directly
|
|
272
|
+
-- (provision_agent rejects system) and assert rotation raises 0A000 and mints nothing.
|
|
272
273
|
reset role;
|
|
273
274
|
do $$
|
|
274
275
|
declare
|
|
@@ -288,12 +289,12 @@ begin
|
|
|
288
289
|
perform * from agent_board.rotate_agent_token(v_system_agent_id);
|
|
289
290
|
raise exception 'rotate_agent_token unexpectedly succeeded for a system principal';
|
|
290
291
|
exception
|
|
291
|
-
when sqlstate '
|
|
292
|
+
when sqlstate '0A000' then
|
|
292
293
|
v_raised := true;
|
|
293
294
|
end;
|
|
294
295
|
|
|
295
296
|
if not v_raised then
|
|
296
|
-
raise exception 'rotate_agent_token did not fail closed with sqlstate
|
|
297
|
+
raise exception 'rotate_agent_token did not fail closed with sqlstate 0A000 (deprecated) for a system principal';
|
|
297
298
|
end if;
|
|
298
299
|
|
|
299
300
|
if exists (
|
|
@@ -304,7 +305,7 @@ begin
|
|
|
304
305
|
end
|
|
305
306
|
$$;
|
|
306
307
|
|
|
307
|
-
select pass('AUTHRPC rotate_agent_token
|
|
308
|
+
select pass('AUTHRPC rotate_agent_token is deprecated (0A000) and mints no credential');
|
|
308
309
|
|
|
309
310
|
select finish();
|
|
310
311
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
-- MBAUTHZ SL-1 (Lane A) pgTAP: board_memberships.role, boards.role_gate_enforced,
|
|
2
|
+
-- and the role gate on invite_board_member/resolve_board_request.
|
|
3
|
+
create extension if not exists pgtap with schema extensions;
|
|
4
|
+
set search_path = extensions, public, agent_board;
|
|
5
|
+
|
|
6
|
+
begin;
|
|
7
|
+
|
|
8
|
+
select plan(13);
|
|
9
|
+
|
|
10
|
+
create temp table _board_role_fixture (
|
|
11
|
+
board uuid,
|
|
12
|
+
creator_agent uuid,
|
|
13
|
+
member_agent uuid,
|
|
14
|
+
admin_agent uuid,
|
|
15
|
+
target_agent uuid,
|
|
16
|
+
other_agent uuid,
|
|
17
|
+
creator_user uuid,
|
|
18
|
+
member_user uuid,
|
|
19
|
+
admin_user uuid
|
|
20
|
+
) on commit drop;
|
|
21
|
+
|
|
22
|
+
do $$
|
|
23
|
+
declare
|
|
24
|
+
v_suffix text := replace(substr(gen_random_uuid()::text, 1, 8), '-', '');
|
|
25
|
+
v_creator_user uuid;
|
|
26
|
+
v_member_user uuid;
|
|
27
|
+
v_admin_user uuid;
|
|
28
|
+
v_creator uuid := gen_random_uuid();
|
|
29
|
+
v_member uuid := gen_random_uuid();
|
|
30
|
+
v_admin uuid := gen_random_uuid();
|
|
31
|
+
v_target uuid := gen_random_uuid();
|
|
32
|
+
v_other uuid := gen_random_uuid();
|
|
33
|
+
v_board uuid;
|
|
34
|
+
begin
|
|
35
|
+
v_creator_user := public.ensure_github_user('br-creator-' || v_suffix, 'br-creator-' || v_suffix || '@example.test', 'br-creator-' || v_suffix, 'BR Creator');
|
|
36
|
+
v_member_user := public.ensure_github_user('br-member-' || v_suffix, 'br-member-' || v_suffix || '@example.test', 'br-member-' || v_suffix, 'BR Member');
|
|
37
|
+
v_admin_user := public.ensure_github_user('br-admin-' || v_suffix, 'br-admin-' || v_suffix || '@example.test', 'br-admin-' || v_suffix, 'BR Admin');
|
|
38
|
+
|
|
39
|
+
insert into agent_board.agents(id, agent_type, handle, display_name, status, auth_user_id, owner_user_id)
|
|
40
|
+
values
|
|
41
|
+
(v_creator, 'agent', 'br-creator-' || v_suffix, 'BR Creator', 'active', v_creator_user, v_creator_user),
|
|
42
|
+
(v_member, 'agent', 'br-member-' || v_suffix, 'BR Member', 'active', v_member_user, v_member_user),
|
|
43
|
+
(v_admin, 'agent', 'br-admin-' || v_suffix, 'BR Admin', 'active', v_admin_user, v_admin_user),
|
|
44
|
+
(v_target, 'agent', 'br-target-' || v_suffix, 'BR Target', 'active', null, null),
|
|
45
|
+
(v_other, 'agent', 'br-other-' || v_suffix, 'BR Other', 'active', null, null);
|
|
46
|
+
|
|
47
|
+
select board_id into v_board
|
|
48
|
+
from agent_board.create_board(v_creator, 'br-board-' || v_suffix, 'BR Board', 'board role test', '{}'::jsonb, 'private');
|
|
49
|
+
|
|
50
|
+
-- Creator + other memberships inserted with the column DEFAULT (member) to
|
|
51
|
+
-- exercise the one-time backfill; member/admin get explicit roles for gate tests.
|
|
52
|
+
insert into agent_board.board_memberships(board_id, agent_id, membership_state, created_by_agent_id)
|
|
53
|
+
values
|
|
54
|
+
(v_board, v_creator, 'joined', v_creator),
|
|
55
|
+
(v_board, v_other, 'joined', v_creator);
|
|
56
|
+
insert into agent_board.board_memberships(board_id, agent_id, membership_state, created_by_agent_id, role)
|
|
57
|
+
values
|
|
58
|
+
(v_board, v_member, 'joined', v_creator, 'member'),
|
|
59
|
+
(v_board, v_admin, 'joined', v_creator, 'admin');
|
|
60
|
+
|
|
61
|
+
insert into _board_role_fixture values
|
|
62
|
+
(v_board, v_creator, v_member, v_admin, v_target, v_other, v_creator_user, v_member_user, v_admin_user);
|
|
63
|
+
end
|
|
64
|
+
$$;
|
|
65
|
+
|
|
66
|
+
-- Structure -----------------------------------------------------------------
|
|
67
|
+
select has_column('agent_board', 'board_memberships', 'role', 'board_memberships has role column');
|
|
68
|
+
select col_type_is('agent_board', 'board_memberships', 'role', 'text', 'role is text');
|
|
69
|
+
select col_has_check('agent_board', 'board_memberships', 'role', 'role is check-constrained');
|
|
70
|
+
select has_column('agent_board', 'boards', 'role_gate_enforced', 'boards has role_gate_enforced flag');
|
|
71
|
+
select col_type_is('agent_board', 'boards', 'role_gate_enforced', 'boolean', 'role_gate_enforced is boolean');
|
|
72
|
+
|
|
73
|
+
-- Default behavior (member membership above was inserted without role) -------
|
|
74
|
+
select is(
|
|
75
|
+
(select role from agent_board.board_memberships bm join _board_role_fixture f on bm.agent_id = f.member_agent and bm.board_id = f.board),
|
|
76
|
+
'member', 'explicit member role persists');
|
|
77
|
+
|
|
78
|
+
-- One-time backfill: creator membership -> owner; other membership -> member.
|
|
79
|
+
update agent_board.board_memberships bm
|
|
80
|
+
set role = 'owner'
|
|
81
|
+
from agent_board.boards b
|
|
82
|
+
where bm.board_id = b.id
|
|
83
|
+
and bm.agent_id = b.created_by_agent_id
|
|
84
|
+
and bm.role <> 'owner';
|
|
85
|
+
|
|
86
|
+
select is(
|
|
87
|
+
(select role from agent_board.board_memberships bm join _board_role_fixture f on bm.agent_id = f.creator_agent and bm.board_id = f.board),
|
|
88
|
+
'owner', 'backfill sets creator membership role to owner');
|
|
89
|
+
select is(
|
|
90
|
+
(select role from agent_board.board_memberships bm join _board_role_fixture f on bm.agent_id = f.other_agent and bm.board_id = f.board),
|
|
91
|
+
'member', 'backfill leaves non-creator membership as member');
|
|
92
|
+
|
|
93
|
+
-- Gate: flag=false (default) preserves any-active-member behavior ------------
|
|
94
|
+
-- Non-creator member (role member) may invite when the flag is off.
|
|
95
|
+
select set_config('request.jwt.claim.sub', (select member_user from _board_role_fixture)::text, true);
|
|
96
|
+
select lives_ok(
|
|
97
|
+
(select format($q$select agent_board.invite_board_member(%L::uuid, %L::uuid, %L::uuid, '{}'::jsonb)$q$, board, target_agent, creator_agent) from _board_role_fixture),
|
|
98
|
+
'flag off: active member (role member) may invite');
|
|
99
|
+
|
|
100
|
+
-- Service_role / null actor (no agent maps to this sub) bypasses.
|
|
101
|
+
select set_config('request.jwt.claim.sub', gen_random_uuid()::text, true);
|
|
102
|
+
select lives_ok(
|
|
103
|
+
(select format($q$select agent_board.invite_board_member(%L::uuid, %L::uuid, %L::uuid, '{}'::jsonb)$q$, board, target_agent, creator_agent) from _board_role_fixture),
|
|
104
|
+
'flag off: service_role/null actor may invite');
|
|
105
|
+
|
|
106
|
+
-- Gate: flag=true requires owner/admin ---------------------------------------
|
|
107
|
+
update agent_board.boards set role_gate_enforced = true
|
|
108
|
+
where id = (select board from _board_role_fixture);
|
|
109
|
+
|
|
110
|
+
select set_config('request.jwt.claim.sub', (select member_user from _board_role_fixture)::text, true);
|
|
111
|
+
select throws_ok(
|
|
112
|
+
(select format($q$select agent_board.invite_board_member(%L::uuid, %L::uuid, %L::uuid, '{}'::jsonb)$q$, board, target_agent, creator_agent) from _board_role_fixture),
|
|
113
|
+
'42501', null,
|
|
114
|
+
'flag on: role member actor is denied invite');
|
|
115
|
+
|
|
116
|
+
select set_config('request.jwt.claim.sub', (select admin_user from _board_role_fixture)::text, true);
|
|
117
|
+
select lives_ok(
|
|
118
|
+
(select format($q$select agent_board.invite_board_member(%L::uuid, %L::uuid, %L::uuid, '{}'::jsonb)$q$, board, target_agent, creator_agent) from _board_role_fixture),
|
|
119
|
+
'flag on: role admin actor may invite');
|
|
120
|
+
|
|
121
|
+
-- Service_role / null actor still bypasses even with the flag on.
|
|
122
|
+
select set_config('request.jwt.claim.sub', gen_random_uuid()::text, true);
|
|
123
|
+
select lives_ok(
|
|
124
|
+
(select format($q$select agent_board.invite_board_member(%L::uuid, %L::uuid, %L::uuid, '{}'::jsonb)$q$, board, target_agent, creator_agent) from _board_role_fixture),
|
|
125
|
+
'flag on: service_role/null actor still bypasses');
|
|
126
|
+
|
|
127
|
+
select finish();
|
|
128
|
+
|
|
129
|
+
rollback;
|