Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aQMM1dPXaPiXVn6DwwtLd Assistant: claude-code Assistant-Model: opus Assistant-Process: 715613@bnt-lap001 Assistant-Session: fabd95c1-4c9e-4080-8849-8707ae025f80
4 KiB
| id | type | title | domain | repo | status | owner | topic_slug | planning_priority | planning_order | depends_on_workplans | related_workplans | created | updated | state_hub_workstream_id | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FLEX-WP-0022 | workplan | Tenant scoping is unstated in tenant-engine and untested in two more packages | infotech | flex-auth | proposed | claude | netkingdom | P1 | 220 |
|
|
2026-09-06 | 2026-09-06 | 804c588c-f47a-50c4-bdd7-51b24bbf9539 |
FLEX-WP-0022 — Tenant scoping is unstated in tenant-engine and untested in two more packages
Opened by the sweep in FLEX-DEC-2026-008, which found
secrets-engine.catalog-lane.lifecycle v1 allowing a foreign tenant and then
asked whether the other packages shared the defect.
What the sweep found
| Package | Fixture tenants | Tenant rule | State |
|---|---|---|---|
secrets-engine |
3 distinct | added at v2 | fixed, FLEX-DEC-2026-008 |
qonto-assistant |
2 distinct | wrong_tenant |
fine |
user-engine |
2 distinct | cross_tenant |
fine |
ops-warden |
constant | wrong_tenant |
rule real, fixtures do not vary it |
railiance-platform |
constant | wrong_tenant |
same |
tenant-engine |
constant | none | deployed, unscoped |
Verified against tenant-engine: an allowed tenant.create re-sent under
tenant: tenant:coulomb returns allow / write_api_policy_matched.
Why tenant-engine is not the same fix
secrets-engine sends its own calling identity's tenant, so a constant
known_tenant is the right rule. tenant-engine is different in kind: its
subjects all sit in tenant:platform while its fixtures send
tenant:friendly:binky, so the request tenant names the target of the
operation. A service whose purpose is creating and retiring tenants acts across
them by design, and a constant would break it on its first real call.
The defect today is therefore not "the rule is missing" but "nobody can tell
whether it is missing": a deliberate cross-tenant scope and an omitted rule
look identical in the artifact. That is the same publishing-shape argument
gate-house made for §12's derived-artifact rule.
1. Get the intended tenant relation from tenant-engine
id: FLEX-WP-0022-T01
status: todo
priority: high
state_hub_task_id: "a84dcee5-9426-5b30-8dd3-f4c076d00174"
Owner: flex-auth to ask; tenant-engine owns the answer.
- Ask what the CheckRequest
tenantdenotes on the write API: the caller's tenant, the target tenant record, or the tenant a guardrail applies to. - Ask whether any of the nine write actions must be refused cross-tenant, and
whether
tenant.guardrail.read(whichflex-authitself calls) differs.
Gate: the relation is named by tenant-engine, not inferred here. This is the
FLEX-WP-0021-T01 rule applied to a field rather than to an action list.
2. Encode the relation, or record that there is none
id: FLEX-WP-0022-T02
status: wait
priority: high
state_hub_task_id: "712ac826-845f-54bd-8446-f11258d21eb4"
Owner: flex-auth.
If a relation exists, encode it in tenant-engine.write-api.mutate as a new
version — fail-open corrections are visible as version changes
(FLEX-DEC-2026-008) — with a fixture per side.
If the scope is genuinely unrestricted, say so in the package: a stated "this package is deliberately cross-tenant, because the caller administers tenants" is a rule a reviewer can check. Silence is not.
Either way the fixtures must vary tenant, so the suite reports on the field.
3. Vary tenant in the two suites that hold it constant
id: FLEX-WP-0022-T03
status: todo
priority: medium
state_hub_task_id: "3058f171-99d2-526b-a1bb-bd7aed87d10a"
Owner: flex-auth.
ops-warden and railiance-platform have working wrong_tenant rules
exercised only by Rego tests. Add a wrong-tenant deny fixture to each so the
fixture suite covers what the rule claims. No policy change and no version bump:
the behaviour is already correct, only the evidence is thin.
Gate: no package's fixture suite holds tenant constant.