feat(sealed): sealed column on triggers + routes (§11 tail M1)
A group template can be marked `sealed = true` so the per-app suppression filters skip it — closing the advisory-by-default compliance footgun the suppression review flagged. Only meaningful on a group-owned template; existing rows default unsealed. Consumption gates land in M3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
19
crates/manager-core/migrations/0059_sealed_templates.sql
Normal file
19
crates/manager-core/migrations/0059_sealed_templates.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- §11 tail (v1.2 Hierarchies): `sealed` (mandatory) group templates.
|
||||||
|
--
|
||||||
|
-- Per-app opt-out (0058_template_suppressions) made an inherited group TRIGGER
|
||||||
|
-- or ROUTE template advisory-by-default: it runs on a descendant *unless* that
|
||||||
|
-- descendant declares a `[suppress]` declining it. That is a compliance footgun
|
||||||
|
-- — a group's audit / security / rate-limit template can be silently opted out
|
||||||
|
-- of by the very tenant it is meant to police.
|
||||||
|
--
|
||||||
|
-- A `sealed` template closes the gap: the two suppression filters skip a sealed
|
||||||
|
-- row, so it fires / serves on every descendant regardless of any suppression.
|
||||||
|
-- The column is only meaningful on a group-owned template (`group_id IS NOT
|
||||||
|
-- NULL`); an app-owned row is never inherited, so sealing it is meaningless and
|
||||||
|
-- rejected at apply. Existing rows default to unsealed (the prior behaviour).
|
||||||
|
--
|
||||||
|
-- * triggers.sealed — a sealed group trigger template is never suppressible.
|
||||||
|
-- * routes.sealed — a sealed group route template is never suppressible.
|
||||||
|
|
||||||
|
ALTER TABLE triggers ADD COLUMN sealed BOOLEAN NOT NULL DEFAULT FALSE;
|
||||||
|
ALTER TABLE routes ADD COLUMN sealed BOOLEAN NOT NULL DEFAULT FALSE;
|
||||||
@@ -342,6 +342,7 @@ table: routes
|
|||||||
dispatch_mode: text NOT NULL default='sync'::text
|
dispatch_mode: text NOT NULL default='sync'::text
|
||||||
enabled: boolean NOT NULL default=true
|
enabled: boolean NOT NULL default=true
|
||||||
group_id: uuid NULL
|
group_id: uuid NULL
|
||||||
|
sealed: boolean NOT NULL default=false
|
||||||
|
|
||||||
table: script_imports
|
table: script_imports
|
||||||
app_id: uuid NOT NULL
|
app_id: uuid NOT NULL
|
||||||
@@ -406,6 +407,7 @@ table: triggers
|
|||||||
updated_at: timestamp with time zone NOT NULL default=now()
|
updated_at: timestamp with time zone NOT NULL default=now()
|
||||||
name: text NOT NULL default=(gen_random_uuid())::text
|
name: text NOT NULL default=(gen_random_uuid())::text
|
||||||
group_id: uuid NULL
|
group_id: uuid NULL
|
||||||
|
sealed: boolean NOT NULL default=false
|
||||||
|
|
||||||
table: vars
|
table: vars
|
||||||
id: uuid NOT NULL default=gen_random_uuid()
|
id: uuid NOT NULL default=gen_random_uuid()
|
||||||
@@ -931,3 +933,4 @@ constraints on vars:
|
|||||||
0056: group triggers
|
0056: group triggers
|
||||||
0057: group routes
|
0057: group routes
|
||||||
0058: template suppressions
|
0058: template suppressions
|
||||||
|
0059: sealed templates
|
||||||
|
|||||||
Reference in New Issue
Block a user