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
112 lines
4 KiB
Markdown
112 lines
4 KiB
Markdown
---
|
|
id: FLEX-WP-0022
|
|
type: workplan
|
|
title: "Tenant scoping is unstated in tenant-engine and untested in two more packages"
|
|
domain: infotech
|
|
repo: flex-auth
|
|
status: proposed
|
|
owner: claude
|
|
topic_slug: netkingdom
|
|
planning_priority: P1
|
|
planning_order: 220
|
|
depends_on_workplans:
|
|
- FLEX-WP-0021
|
|
related_workplans:
|
|
- FLEX-WP-0010
|
|
- FLEX-WP-0014
|
|
created: "2026-09-06"
|
|
updated: "2026-09-06"
|
|
state_hub_workstream_id: "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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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
|
|
|
|
```task
|
|
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.
|