flex-auth/workplans/FLEX-WP-0022-tenant-scope-coverage.md
tegwick cc311056b9
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
chore(consistency): register FLEX-WP-0022 and refresh work records
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
2026-09-06 20:41:05 +02:00

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
FLEX-WP-0021
FLEX-WP-0010
FLEX-WP-0014
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 tenant denotes 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 (which flex-auth itself 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.