Cover wrong-tenant denials in ops-warden and railiance-platform fixtures.

FLEX-WP-0022-T03: the rules already refused a foreign tenant; the fixture
suites never varied the field. No policy or version change. Asked
tenant-engine to name the CheckRequest tenant relation for T01/T02.

Assistant: grok
Assistant-Session: 01a0a6cb-0334-72c0-83b0-2df57474a0f6
This commit is contained in:
tegwick 2026-09-15 23:38:48 +02:00
parent 6fd3a0cbc4
commit 0e020b2d8c
8 changed files with 117 additions and 8 deletions

View file

@ -28,6 +28,7 @@ flex-auth validate --kind subject-manifest --file examples/ops-warden/subject_ma
flex-auth load-registry --file examples/ops-warden/registry_snapshot.json flex-auth load-registry --file examples/ops-warden/registry_snapshot.json
flex-auth test-policy --file examples/ops-warden/policy_package.md flex-auth test-policy --file examples/ops-warden/policy_package.md
flex-auth check --registry examples/ops-warden/registry_snapshot.json --policy examples/ops-warden/policy_package.md --request examples/ops-warden/check_request_allow_adm.json flex-auth check --registry examples/ops-warden/registry_snapshot.json --policy examples/ops-warden/policy_package.md --request examples/ops-warden/check_request_allow_adm.json
flex-auth check --registry examples/ops-warden/registry_snapshot.json --policy examples/ops-warden/policy_package.md --request examples/ops-warden/check_request_deny_wrong_tenant.json
``` ```
The fixture public-key fingerprints are examples only. Do not put real keys, The fixture public-key fingerprints are examples only. Do not put real keys,

View file

@ -0,0 +1,23 @@
{
"id": "check:ops-warden-wrong-tenant",
"tenant": "tenant:other",
"subject": {
"id": "platform-steward",
"type": "adm"
},
"action": "sign",
"resource": {
"id": "ssh-cert:actor/platform-steward",
"type": "ssh-certificate",
"system": "ops-warden"
},
"context": {
"principals": [
"platform",
"root"
],
"actor_type": "adm",
"ttl_hours": 4,
"pubkey_fingerprint": "SHA256:example-adm-fingerprint"
}
}

View file

@ -394,5 +394,50 @@
"effect": "audit_only", "effect": "audit_only",
"reason": "advisory_would_signing_policy_matched" "reason": "advisory_would_signing_policy_matched"
} }
},
{
"id": "fixture:ops-warden-wrong-tenant-deny",
"request": {
"id": "check:ops-warden-wrong-tenant",
"tenant": "tenant:other",
"subject": {
"id": "platform-steward",
"type": "adm"
},
"action": "sign",
"resource": {
"id": "ssh-cert:actor/platform-steward",
"type": "ssh-certificate",
"system": "ops-warden",
"attributes": {
"actor_id": "platform-steward",
"actor_type": "adm",
"allowed_subjects": [
"platform-steward",
"iam:platform-steward"
],
"allowed_principals": [
"platform",
"root"
],
"max_ttl_hours": 8,
"security_zone": "z2-protected",
"security_zone_admission": "satisfied"
}
},
"context": {
"principals": [
"platform",
"root"
],
"actor_type": "adm",
"ttl_hours": 4,
"pubkey_fingerprint": "SHA256:example-adm-fingerprint"
}
},
"expect": {
"effect": "deny",
"reason": "wrong_tenant"
}
} }
] ]

View file

@ -2,7 +2,8 @@
This package provides the flex-auth side of `FLEX-WP-0012`: registered grant This package provides the flex-auth side of `FLEX-WP-0012`: registered grant
metadata, representative requester subjects, a default-deny `issue` policy, metadata, representative requester subjects, a default-deny `issue` policy,
and fixtures for TTL, actor type, purpose, delivery mode, and unknown grants. and fixtures for TTL, actor type, purpose, delivery mode, unknown grants, and
wrong tenant.
The wire translation is intentionally outside the policy. Both candidate The wire translation is intentionally outside the policy. Both candidate
integration shapes must emit `requested_ttl_seconds` as a positive number; integration shapes must emit `requested_ttl_seconds` as a positive number;
@ -13,4 +14,5 @@ go run ./cmd/flex-auth load-registry --file examples/railiance-platform/registry
go run ./cmd/flex-auth test-policy --file examples/railiance-platform/policy_package.md go run ./cmd/flex-auth test-policy --file examples/railiance-platform/policy_package.md
go run ./cmd/flex-auth check --registry examples/railiance-platform/registry_snapshot.json --policy examples/railiance-platform/policy_package.md --request examples/railiance-platform/check_request_allow.json go run ./cmd/flex-auth check --registry examples/railiance-platform/registry_snapshot.json --policy examples/railiance-platform/policy_package.md --request examples/railiance-platform/check_request_allow.json
go run ./cmd/flex-auth check --registry examples/railiance-platform/registry_snapshot.json --policy examples/railiance-platform/policy_package.md --request examples/railiance-platform/check_request_deny_unknown.json go run ./cmd/flex-auth check --registry examples/railiance-platform/registry_snapshot.json --policy examples/railiance-platform/policy_package.md --request examples/railiance-platform/check_request_deny_unknown.json
go run ./cmd/flex-auth check --registry examples/railiance-platform/registry_snapshot.json --policy examples/railiance-platform/policy_package.md --request examples/railiance-platform/check_request_deny_wrong_tenant.json
``` ```

View file

@ -0,0 +1,21 @@
{
"id": "check:credential-grant-wrong-tenant-http-shape",
"tenant": "tenant:other",
"subject": {
"id": "agent:codex/railiance-platform",
"type": "Agent"
},
"action": "issue",
"resource": {
"id": "credential-grant:rapp-postgres/audit-core-runtime",
"type": "credential-grant",
"system": "railiance-platform"
},
"context": {
"actor_type": "approved-agent",
"bound_subject": "agent:codex/railiance-platform",
"purpose": "audit-core-runtime",
"delivery_mode": "exec-env",
"requested_ttl_seconds": 900
}
}

View file

@ -57,3 +57,9 @@
type: credential-grant type: credential-grant
system: railiance-platform system: railiance-platform
expect: {effect: deny, reason: unknown_grant} expect: {effect: deny, reason: unknown_grant}
- id: fixture:credential-grant-wrong-tenant-deny
request:
<<: *allow_request
id: check:credential-grant-wrong-tenant-deny
tenant: tenant:other
expect: {effect: deny, reason: wrong_tenant}

View file

@ -86,8 +86,8 @@ func TestOpsWardenPolicyPackageMarkdownValidates(t *testing.T) {
if pkg.Metadata.Namespace != "ops-warden:ssh-certificate" { if pkg.Metadata.Namespace != "ops-warden:ssh-certificate" {
t.Fatalf("metadata.Namespace = %q; want ops-warden:ssh-certificate", pkg.Metadata.Namespace) t.Fatalf("metadata.Namespace = %q; want ops-warden:ssh-certificate", pkg.Metadata.Namespace)
} }
if len(pkg.Validation.Fixtures) != 9 { if len(pkg.Validation.Fixtures) != 10 {
t.Fatalf("Validation.Fixtures len = %d; want 9", len(pkg.Validation.Fixtures)) t.Fatalf("Validation.Fixtures len = %d; want 10", len(pkg.Validation.Fixtures))
} }
for _, fixture := range pkg.Validation.Fixtures { for _, fixture := range pkg.Validation.Fixtures {
if !fixture.Passed { if !fixture.Passed {

View file

@ -4,8 +4,8 @@ type: workplan
title: "Tenant scoping is unstated in tenant-engine and untested in two more packages" title: "Tenant scoping is unstated in tenant-engine and untested in two more packages"
domain: infotech domain: infotech
repo: flex-auth repo: flex-auth
status: proposed status: active
flavor: planning flavor: implementation
depends_on: depends_on:
- FLEX-WP-0021 - FLEX-WP-0021
owner: claude owner: claude
@ -18,7 +18,7 @@ related_workplans:
- FLEX-WP-0010 - FLEX-WP-0010
- FLEX-WP-0014 - FLEX-WP-0014
created: "2026-09-06" created: "2026-09-06"
updated: "2026-09-06" updated: "2026-09-15"
state_hub_workstream_id: "804c588c-f47a-50c4-bdd7-51b24bbf9539" state_hub_workstream_id: "804c588c-f47a-50c4-bdd7-51b24bbf9539"
--- ---
@ -60,7 +60,7 @@ look identical in the artifact. That is the same publishing-shape argument
```task ```task
id: FLEX-WP-0022-T01 id: FLEX-WP-0022-T01
status: todo status: progress
priority: high priority: high
state_hub_task_id: "a84dcee5-9426-5b30-8dd3-f4c076d00174" state_hub_task_id: "a84dcee5-9426-5b30-8dd3-f4c076d00174"
``` ```
@ -75,6 +75,11 @@ Owner: `flex-auth` to ask; `tenant-engine` owns the answer.
Gate: the relation is named by `tenant-engine`, not inferred here. This is the 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. `FLEX-WP-0021-T01` rule applied to a field rather than to an action list.
2026-09-15: asked `tenant-engine` to name the relation
(`e8ba6a53-0093-4dc0-ad70-01f6b8c8e76b`). Their live
`FlexAuthWriteAuthorizer.authorize` copies `tenant_id` onto both
`CheckRequest.tenant` and `resource.id`. That is observation, not admission.
## 2. Encode the relation, or record that there is none ## 2. Encode the relation, or record that there is none
```task ```task
@ -100,7 +105,7 @@ Either way the fixtures must vary `tenant`, so the suite reports on the field.
```task ```task
id: FLEX-WP-0022-T03 id: FLEX-WP-0022-T03
status: todo status: done
priority: medium priority: medium
state_hub_task_id: "3058f171-99d2-526b-a1bb-bd7aed87d10a" state_hub_task_id: "3058f171-99d2-526b-a1bb-bd7aed87d10a"
``` ```
@ -113,3 +118,9 @@ fixture suite covers what the rule claims. No policy change and no version bump:
the behaviour is already correct, only the evidence is thin. the behaviour is already correct, only the evidence is thin.
Gate: no package's fixture suite holds `tenant` constant. Gate: no package's fixture suite holds `tenant` constant.
2026-09-15: added `fixture:ops-warden-wrong-tenant-deny` and
`fixture:credential-grant-wrong-tenant-deny` plus matching
`check_request_deny_wrong_tenant.json` files. Both suites now vary `tenant`.
`test-policy` and `flex-auth check` return `deny` / `wrong_tenant`. No policy
or version change.