2026-08-10 20:11:30 +02:00
|
|
|
|
---
|
|
|
|
|
|
id: FLEX-WP-0010
|
|
|
|
|
|
type: workplan
|
|
|
|
|
|
title: "Authorize tenant-engine lifecycle actions"
|
|
|
|
|
|
domain: infotech
|
|
|
|
|
|
repo: flex-auth
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
status: finished
|
2026-08-10 20:11:30 +02:00
|
|
|
|
owner: codex
|
|
|
|
|
|
topic_slug: netkingdom
|
|
|
|
|
|
planning_priority: P1
|
|
|
|
|
|
planning_order: 100
|
|
|
|
|
|
depends_on_workplans:
|
|
|
|
|
|
- FLEX-WP-0008
|
|
|
|
|
|
related_workplans:
|
|
|
|
|
|
- TEN-WP-0005
|
|
|
|
|
|
- USER-WP-0021
|
|
|
|
|
|
created: "2026-08-10"
|
|
|
|
|
|
updated: "2026-08-10"
|
2026-08-25 20:10:35 +02:00
|
|
|
|
state_hub_workstream_id: "fdabae84-dc9e-5ccd-81df-8ae7e66b90b8"
|
2026-08-10 20:11:30 +02:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
# FLEX-WP-0010 - Authorize tenant-engine lifecycle actions
|
|
|
|
|
|
|
|
|
|
|
|
Extend the existing `tenant-engine` policy package (FLEX-WP-0008-T02) with the
|
|
|
|
|
|
three tenant lifecycle actions `TEN-WP-0005` introduced. Until they exist here,
|
|
|
|
|
|
every lifecycle mutation resolves to `deny` with `unknown_action` — correct
|
|
|
|
|
|
fail-closed behaviour, not a defect, but it means tenant-engine's new update
|
|
|
|
|
|
and retirement endpoints cannot perform a single write in production.
|
|
|
|
|
|
|
|
|
|
|
|
**Requested by:** `tenant-engine` (TEN-WP-0005, T01–T04 complete and merged).
|
|
|
|
|
|
**Blocks:** `TEN-WP-0005-T05` (production rollout), and through it
|
|
|
|
|
|
`USER-WP-0021` (user-engine platform operator UI/API).
|
|
|
|
|
|
|
|
|
|
|
|
## Requirements from tenant-engine
|
|
|
|
|
|
|
|
|
|
|
|
Three new actions, all on the existing `tenant` resource type, all against
|
|
|
|
|
|
`system: "tenant-engine"`:
|
|
|
|
|
|
|
|
|
|
|
|
| Action | Resource type | HTTP surface |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `tenant.update` | `tenant` | `PATCH /tenants/{tenant_id}` |
|
|
|
|
|
|
| `tenant.retire` | `tenant` | `POST /tenants/{tenant_id}/retire` |
|
|
|
|
|
|
| `tenant.reactivate` | `tenant` | `POST /tenants/{tenant_id}/reactivate` |
|
|
|
|
|
|
|
|
|
|
|
|
These strings are already live in
|
|
|
|
|
|
`tenant-engine/src/tenant_engine/authz.py`'s `_RESOURCE_TYPES` mapping —
|
|
|
|
|
|
they are the exact values `FlexAuthWriteAuthorizer` sends. Match them
|
|
|
|
|
|
verbatim; do not let the two repos invent different strings for the same
|
|
|
|
|
|
action (the coordination rule FLEX-WP-0008-T01 already established).
|
|
|
|
|
|
|
|
|
|
|
|
The `CheckRequest` shape is unchanged from FLEX-WP-0008: same
|
|
|
|
|
|
`FlexAuthCheckClient`, same `subject_type: "service"`, `resource_id` =
|
|
|
|
|
|
`tenant_id`. No new request fields, no schema change.
|
|
|
|
|
|
|
|
|
|
|
|
**Why three actions rather than one `tenant.write`:** tenant-engine
|
|
|
|
|
|
deliberately separated them so policy *can* permit an operator to rename a
|
|
|
|
|
|
tenant without thereby permitting them to retire it. Consumer contract:
|
|
|
|
|
|
`tenant-engine/docs/tenant-lifecycle-api.md`.
|
|
|
|
|
|
|
|
|
|
|
|
**Honest caveat on what this buys today:** under FLEX-WP-0008-T02's current
|
|
|
|
|
|
model there is exactly one known operator (the `tenant-engine` service
|
|
|
|
|
|
identity) and no `assurance` claim, so all three actions will resolve
|
|
|
|
|
|
identically once added. The separation is a seam for later, not
|
|
|
|
|
|
differentiated authorization now. Adding the actions is what unblocks
|
|
|
|
|
|
production; differentiating them is T02 below, and may well close as "not
|
|
|
|
|
|
yet, and here is why".
|
|
|
|
|
|
|
|
|
|
|
|
## T01 - Extend the policy package with the lifecycle actions
|
|
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
|
id: FLEX-WP-0010-T01
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
status: done
|
2026-08-10 20:11:30 +02:00
|
|
|
|
priority: high
|
2026-08-25 20:10:35 +02:00
|
|
|
|
state_hub_task_id: "8deb9564-658e-5eff-8ef7-94838bee05cc"
|
2026-08-10 20:11:30 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Add `tenant.update`, `tenant.retire`, and `tenant.reactivate` to
|
|
|
|
|
|
`examples/tenant-engine/policy_package.md`'s `valid_actions` set and to the
|
|
|
|
|
|
frontmatter `actions:` list. Extend the `caring.capabilities` list if the
|
|
|
|
|
|
existing vocabulary (`Create`/`Grant`/`Revoke`/`Bind`/`Audit`) does not
|
|
|
|
|
|
already cover an update/retire/reactivate shape — a judgement call for this
|
|
|
|
|
|
repo, not pre-specified here.
|
|
|
|
|
|
|
|
|
|
|
|
Update `examples/tenant-engine/subject_manifest.yaml`'s subject metadata
|
|
|
|
|
|
description, which currently enumerates the original four actions.
|
|
|
|
|
|
|
|
|
|
|
|
Update `docs/tenant-engine-action-vocabulary.md` with the three actions, their
|
|
|
|
|
|
resource type, and the HTTP surface each gates. Keep the existing note that
|
|
|
|
|
|
this policy governs *who may call tenant-engine's admin API*, not a tenant's
|
|
|
|
|
|
own `PLTF`/`IAM`/`VEN`/`CUS` capability roles — the lifecycle actions do not
|
|
|
|
|
|
change that boundary and should not be read as doing so.
|
|
|
|
|
|
|
|
|
|
|
|
Rebuild `examples/tenant-engine/registry_snapshot.json`.
|
|
|
|
|
|
|
|
|
|
|
|
Done when `valid_actions` carries all seven actions and the vocabulary doc
|
|
|
|
|
|
and subject manifest no longer describe only four.
|
|
|
|
|
|
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
Done 2026-08-10: all seven actions are in `valid_actions`, the frontmatter
|
|
|
|
|
|
`actions:` list, and the protected-system manifest. CARING capabilities were
|
|
|
|
|
|
extended with `EditAny` (update), `Archive` (retire), and `Restore`
|
|
|
|
|
|
(reactivate) — the existing `Create`/`Grant`/`Revoke`/`Bind` set had no
|
|
|
|
|
|
update or lifecycle shape, and `Archive`/`Restore` name the reversible pair
|
|
|
|
|
|
exactly as tenant-engine implements it. `registry_snapshot.json` was rebuilt
|
|
|
|
|
|
from the two manifests, the subject metadata now enumerates all seven, and
|
|
|
|
|
|
`docs/tenant-engine-action-vocabulary.md` carries the three HTTP surfaces
|
|
|
|
|
|
plus an explicit note that `tenant.retire` asks whether *this caller* may
|
|
|
|
|
|
retire a tenant, not what a *retired tenant* may do.
|
|
|
|
|
|
|
2026-08-10 20:11:30 +02:00
|
|
|
|
## T02 - Decide whether retirement warrants stricter authorization
|
|
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
|
id: FLEX-WP-0010-T02
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
status: done
|
2026-08-10 20:11:30 +02:00
|
|
|
|
priority: medium
|
2026-08-25 20:10:35 +02:00
|
|
|
|
state_hub_task_id: "82d13a89-a344-5797-b10f-390d17b11b73"
|
2026-08-10 20:11:30 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`tenant.retire` is the highest-consequence action in the set: it suspends a
|
|
|
|
|
|
tenant's ability to receive new capability grants and plan changes across the
|
|
|
|
|
|
whole platform. Decide whether it should require anything `tenant.update` does
|
|
|
|
|
|
not — a distinct subject, group, or (once available) assurance level.
|
|
|
|
|
|
|
|
|
|
|
|
Record the decision with its reasoning, in the style of FLEX-WP-0008-T02's
|
|
|
|
|
|
closure note. "No, not until `KEY-WP-0005` gives callers a real
|
|
|
|
|
|
`assurance`-bearing identity to check" is a perfectly good outcome — the point
|
|
|
|
|
|
is that the decision is explicit and recorded rather than defaulted into by
|
|
|
|
|
|
treating all seven actions as interchangeable.
|
|
|
|
|
|
|
|
|
|
|
|
Note that retirement is **reversible** by design (`tenant.reactivate`), and
|
|
|
|
|
|
that tenant-engine hard-deletes nothing — so the blast radius of a wrongly
|
|
|
|
|
|
allowed retirement is recoverable, which is legitimate input to this decision.
|
|
|
|
|
|
|
|
|
|
|
|
Done when the decision and its reasoning are recorded in
|
|
|
|
|
|
`policy_package.md`, and implemented if the answer is "yes, stricter".
|
|
|
|
|
|
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
Done 2026-08-10: **no — `tenant.retire` is authorized by the same rule as the
|
|
|
|
|
|
other six.** Recorded with full reasoning under "Decision: `tenant.retire`
|
|
|
|
|
|
does not require stricter authorization yet" in
|
|
|
|
|
|
`examples/tenant-engine/policy_package.md`. The load-bearing reason is that
|
|
|
|
|
|
there is nothing stricter to check: one service subject, no second operator,
|
|
|
|
|
|
no `assurance` field in the `CheckRequest`. A condition the sole caller
|
|
|
|
|
|
always satisfies would read to a later reviewer as though retirement were
|
|
|
|
|
|
separately controlled when it is not — a false assurance in a package whose
|
|
|
|
|
|
job is inspectability. Retirement being reversible and non-destructive makes
|
|
|
|
|
|
that acceptable. Revisit when `KEY-WP-0005` supplies an assurance-bearing
|
|
|
|
|
|
identity, or when a second `tenant-engine` operator subject is registered.
|
|
|
|
|
|
|
2026-08-10 20:11:30 +02:00
|
|
|
|
## T03 - Fixtures and verification
|
|
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
|
id: FLEX-WP-0010-T03
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
status: done
|
2026-08-10 20:11:30 +02:00
|
|
|
|
priority: high
|
2026-08-25 20:10:35 +02:00
|
|
|
|
state_hub_task_id: "2fbceaf5-514b-5ded-adb1-f4e63ce96160"
|
2026-08-10 20:11:30 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Add `allow`/`deny` fixture pairs to
|
|
|
|
|
|
`examples/tenant-engine/policy_fixtures.yaml` for each of the three actions,
|
|
|
|
|
|
mirroring the existing eight pairs' shape. Cover at minimum: authorized
|
|
|
|
|
|
service subject → `allow`; unknown subject → `deny unknown_subject`; and a
|
|
|
|
|
|
misspelled lifecycle action → `deny unknown_action` (the case that guards
|
|
|
|
|
|
against the two repos drifting apart on action strings).
|
|
|
|
|
|
|
|
|
|
|
|
Verify the way FLEX-WP-0008-T02 did, against the real binary rather than in
|
|
|
|
|
|
isolation: `go build ./cmd/flex-auth`, then `test-policy` (all Rego tests and
|
|
|
|
|
|
fixtures), `load-registry`, and `check` against standalone request files.
|
|
|
|
|
|
|
|
|
|
|
|
Then close the loop end-to-end, which is what `TEN-WP-0005-T05` actually needs
|
|
|
|
|
|
evidence of: run a live `flex-auth serve` with this registry and point a real
|
|
|
|
|
|
`tenant-engine` at it (`TENANT_ENGINE_FLEX_AUTH_URL`), then exercise
|
|
|
|
|
|
`PATCH /tenants/{id}`, `POST .../retire`, and `POST .../reactivate` through
|
|
|
|
|
|
the unmodified `FlexAuthWriteAuthorizer`. tenant-engine's lifecycle endpoints
|
|
|
|
|
|
require `Idempotency-Key` and `If-Match` headers — read the record first and
|
|
|
|
|
|
echo its `ETag` back; `tenant-engine/docs/tenant-lifecycle-api.md` has the
|
|
|
|
|
|
call shapes.
|
|
|
|
|
|
|
|
|
|
|
|
Done when all three lifecycle mutations return a real `allow` from the real
|
|
|
|
|
|
Rego engine over real HTTP, `go test ./...` is green across the repo, and
|
|
|
|
|
|
`gofmt`/`go vet` are clean.
|
|
|
|
|
|
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
Done 2026-08-10: eight fixture pairs added (allow for each of the three
|
|
|
|
|
|
actions, `unknown_subject` deny for each, and two action-drift denies —
|
|
|
|
|
|
`tenant.retired` and `tenant_update`, both `unknown_action`). Five embedded
|
|
|
|
|
|
Rego tests added. `test-policy` reports 11/11 tests and 16/16 fixtures
|
|
|
|
|
|
passing; `load-registry` loads clean; `check` returns the expected decisions
|
|
|
|
|
|
for the two new standalone request files.
|
|
|
|
|
|
|
|
|
|
|
|
End-to-end against a live `flex-auth serve` (127.0.0.1:9098) with a real
|
|
|
|
|
|
`tenant-engine` on `TENANT_ENGINE_FLEX_AUTH_URL`, driven through the
|
|
|
|
|
|
unmodified `FlexAuthWriteAuthorizer` with `Idempotency-Key` and an `If-Match`
|
|
|
|
|
|
echoed from a prior `GET`:
|
|
|
|
|
|
|
|
|
|
|
|
| Call | tenant-engine | flex-auth decision |
|
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
|
| `POST /tenants` | 201 | `decision:174dc9ecb03ed9e5` allow |
|
|
|
|
|
|
| `PATCH /tenants/t-e2e-1` | 200 `active` | `decision:6176c39c2f4d7b15` allow |
|
|
|
|
|
|
| `POST .../retire` | 200 `retired` | `decision:8a801b8ee8455080` allow |
|
|
|
|
|
|
| `POST .../reactivate` | 200 `active` | `decision:c64cf3713cecd970` allow |
|
|
|
|
|
|
| `POST .../retire` as `actor: ops` | 403 `write_denied` | `decision:59d3e99c6416be89` deny `unknown_subject` |
|
|
|
|
|
|
|
|
|
|
|
|
`go test ./...` green across all packages; `gofmt -l` empty; `go vet ./...`
|
|
|
|
|
|
clean. Evidence table mirrored into `examples/tenant-engine/README.md`.
|
|
|
|
|
|
|
2026-08-10 20:11:30 +02:00
|
|
|
|
## T04 - Closure and handoff
|
|
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
|
id: FLEX-WP-0010-T04
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
status: done
|
2026-08-10 20:11:30 +02:00
|
|
|
|
priority: low
|
2026-08-25 20:10:35 +02:00
|
|
|
|
state_hub_task_id: "eb2579cb-b54f-5834-abcc-81954ac34889"
|
2026-08-10 20:11:30 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Confirm T01–T03. Run `statehub fix-consistency`. Notify `tenant-engine` that
|
|
|
|
|
|
`TEN-WP-0005-T05` is unblocked, naming the policy revision — T05's own
|
|
|
|
|
|
done-criteria require the handoff to name the authorization policy revision
|
|
|
|
|
|
alongside the immutable image and API version.
|
Authorize tenant-engine lifecycle actions (FLEX-WP-0010)
Extend the tenant-engine write-API policy package with tenant.update,
tenant.retire, and tenant.reactivate, the three actions TEN-WP-0005
introduced. Until now every lifecycle mutation resolved to deny
unknown_action, blocking TEN-WP-0005-T05 production rollout.
- policy_package.md: three actions in valid_actions and frontmatter;
CARING capabilities extended with EditAny/Archive/Restore
- protected_system_manifest.yaml, subject_manifest.yaml, and the rebuilt
registry_snapshot.json carry all seven actions
- docs/tenant-engine-action-vocabulary.md documents the HTTP surfaces
- 8 new fixture pairs and 5 new Rego tests, including action-drift
guards (tenant.retired, tenant_update -> unknown_action)
T02 decision, recorded in policy_package.md: tenant.retire does NOT get
stricter authorization yet. With one service subject and no assurance
claim in the CheckRequest there is nothing stricter to check, and a
condition the sole caller always satisfies would falsely read as
separate control. Retirement is reversible and non-destructive. Revisit
on KEY-WP-0005 assurance claims or a second operator subject.
Verified: 11/11 Rego tests, 16/16 fixtures, go test ./... green, gofmt
and go vet clean. End-to-end against a live serve with a real
tenant-engine through the unmodified FlexAuthWriteAuthorizer: update
6176c39c2f4d7b15, retire 8a801b8ee8455080, reactivate c64cf3713cecd970
all allow; unregistered actor denied unknown_subject
(59d3e99c6416be89, 403 write_denied).
Handoff revision for TEN-WP-0005-T05: package
tenant-engine.write-api.mutate v1 (ready, caring-0.4.0-rc2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:52:10 +02:00
|
|
|
|
|
|
|
|
|
|
Done 2026-08-10: T01–T03 confirmed. Policy revision for the handoff is
|
|
|
|
|
|
package `tenant-engine.write-api.mutate` **version `v1`**, status `ready`,
|
|
|
|
|
|
profile `caring-0.4.0-rc2`, now carrying all seven actions — the version
|
|
|
|
|
|
string is unchanged because the package is additive and `v1` remains the
|
|
|
|
|
|
activated revision; the identifying fact for TEN-WP-0005-T05 is that `v1` as
|
|
|
|
|
|
of this commit contains `tenant.update`, `tenant.retire`, and
|
2026-08-10 20:55:41 +02:00
|
|
|
|
`tenant.reactivate`.
|
|
|
|
|
|
|
|
|
|
|
|
**Production is not yet serving this policy — stated plainly because
|
|
|
|
|
|
TEN-WP-0005-T05 depends on it.** The policy package is baked into the
|
|
|
|
|
|
flex-auth container image, not mounted from a ConfigMap: the deployed
|
|
|
|
|
|
`flex-auth-tenant-engine` Deployment in namespace `flex-auth` runs image
|
|
|
|
|
|
`@sha256:c25fc34a6cd7e64d955f8723ec70e176a583d5ae71d76280c4e2d89fba0fe0aa`
|
|
|
|
|
|
with `--policy /opt/flex-auth/examples/tenant-engine/policy_package.md`
|
|
|
|
|
|
from that image. Probed live on 2026-08-10 via port-forward:
|
|
|
|
|
|
`tenant.retire` still returns **deny `unknown_action`**, while
|
|
|
|
|
|
`tenant.create` returns allow — i.e. the running instance is the
|
|
|
|
|
|
pre-FLEX-WP-0010 four-action policy.
|
|
|
|
|
|
|
|
|
|
|
|
So `TEN-WP-0005-T05` is unblocked **in source** but not **in the cluster**
|
|
|
|
|
|
until a new image is built from commit `8e127e5` and rolled out. That
|
|
|
|
|
|
rollout is a production deploy that this workplan does not scope (contrast
|
|
|
|
|
|
FLEX-WP-0007 and FLEX-WP-0009-T03, which carried explicit deployment
|
|
|
|
|
|
tasks) and it is deliberately left for an owner decision rather than done
|
|
|
|
|
|
implicitly under a policy-authoring workplan. It is the single remaining
|
|
|
|
|
|
step between this commit and a live lifecycle mutation.
|