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>
194 lines
6.9 KiB
YAML
194 lines
6.9 KiB
YAML
[
|
|
{
|
|
"id": "fixture:tenant-engine-create-allow",
|
|
"request": {
|
|
"id": "check:tenant-engine-create-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.create",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-role-grant-allow",
|
|
"request": {
|
|
"id": "check:tenant-engine-role-grant-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.role.grant",
|
|
"resource": {"id": "t-1", "type": "role-grant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-role-revoke-allow",
|
|
"request": {
|
|
"id": "check:tenant-engine-role-revoke-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.role.revoke",
|
|
"resource": {"id": "t-1", "type": "role-grant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-plan-assign-allow",
|
|
"request": {
|
|
"id": "check:tenant-engine-plan-assign-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.plan.assign",
|
|
"resource": {"id": "t-1", "type": "plan-assignment", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-update-allow",
|
|
"request": {
|
|
"id": "check:tenant-engine-update-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.update",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-retire-allow",
|
|
"request": {
|
|
"id": "check:tenant-engine-retire-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.retire",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-reactivate-allow",
|
|
"request": {
|
|
"id": "check:tenant-engine-reactivate-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.reactivate",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "allow", "reason": "write_api_policy_matched"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-update-unknown-subject-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-update-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "some-other-service", "type": "service"},
|
|
"action": "tenant.update",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "unknown_subject"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-retire-unknown-subject-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-retire-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "some-other-service", "type": "service"},
|
|
"action": "tenant.retire",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "unknown_subject"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-reactivate-unknown-subject-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-reactivate-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "some-other-service", "type": "service"},
|
|
"action": "tenant.reactivate",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "unknown_subject"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-misspelled-lifecycle-action-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-retired-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.retired",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "unknown_action"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-lifecycle-underscore-action-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-underscore-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant_update",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "unknown_action"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-unknown-subject-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-create-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "some-other-service", "type": "service"},
|
|
"action": "tenant.create",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "unknown_subject"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-wrong-system-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-create-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.create",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "some-other-system"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "wrong_system"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-unknown-action-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-delete-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "service"},
|
|
"action": "tenant.delete",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "unknown_action"}
|
|
},
|
|
{
|
|
"id": "fixture:tenant-engine-wrong-subject-type-deny",
|
|
"request": {
|
|
"id": "check:tenant-engine-create-t1",
|
|
"tenant": "tenant:friendly:binky",
|
|
"subject": {"id": "tenant-engine", "type": "human"},
|
|
"action": "tenant.create",
|
|
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"},
|
|
"context": {}
|
|
},
|
|
"expect": {"effect": "deny", "reason": "wrong_subject_type"}
|
|
}
|
|
]
|