tenant-engine/pip-claims.yaml
tegwick 672cf4da6e
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 37s
Implement TEN-WP-0011 security layer conformance
Engine/PIP declaration is now checkable (layer.yaml plus a Tooling-client
scan). Writes persist a decision record or the published fail-closed
stance, live-lookup freshness is published, events_for is tenant-scoped,
and mutation evidence drains to audit-core from a local outbox without
blocking the mutation.

Sender registration is requested as AUDIT-IN-0002. Boundary-contract
amendment is requested as NET-IN-0002.

Assistant: grok
Assistant-Session: 01a04cea-e5e8-7081-a0fc-808ebbc35fa9
2026-08-29 13:02:51 +02:00

80 lines
2.9 KiB
YAML

# tenant-engine — PIP claim freshness contract
#
# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md §9.3, §9.7
# Companion: net-kingdom/SECURITY-COMPANION.md v0.2
# Named from: layer.yaml (pip_claims)
# Validate: tests/test_pip_claims.py
#
# access-engine states a deadline per input class. This file is the input
# class description it is owed for tenant facts.
schema_version: "0.1"
framework: netkingdom-security-layer-model
standard_version: "0.7"
repository: tenant-engine
role: pip
input_classes:
tenant_roles_cached:
surface: "GET /tenants/{id}/roles"
consumer: key-cape
carrying: "IAM Profile v0.3 optional tenant_roles token claim"
lifetime: "the issuing token's lifetime; this engine does not push-invalidate"
cross_request_cache_by_this_engine: false
notes: >-
The token claim is a point-in-time copy. Privileged decisions MUST
not trust it; they use tenant_roles_live.
tenant_roles_live:
surface: "GET /tenants/{id}/roles/live"
consumer: access-engine
carrying: "current active capability roles"
lifetime: "this response only"
cross_request_cache_by_consumer: false
request_scoped_memoization: true
notes: >-
Boundary contract: request-scoped memoization inside one decision is
allowed. Cross-request caching of live-lookup results is not — that
would recreate the staleness the live path exists to avoid (§6.1).
tenant_record:
surface: "GET /tenants/{id}"
consumer: user-engine operator UI and other admin surfaces
carrying: "existence, grouping, lifecycle, metadata, version ETag"
lifetime: "until the ETag changes"
cross_request_cache_by_this_engine: false
tenant_guardrails:
surface: "GET /tenants/{id}/guardrails"
consumer: access-engine
carrying: "effective ceilings per registered limit key"
lifetime: "this response only"
cross_request_cache_by_consumer: false
request_scoped_memoization: true
notes: >-
A ceiling is a claim, never an allow. Unavailability must not be
read as "no limits".
degradation:
store_unavailable:
http_status: 503
body_never: "200 with empty roles or empty limits"
consumer_meaning: "input degradation at access-engine (§9.3); fail to reduced authority"
surfaces:
- tenant_roles_cached
- tenant_roles_live
- tenant_record
- tenant_guardrails
live_lookup_authorization:
action: tenant.role.read.live
check_consumes_tenant_roles: false
reenters_tenant_engine: false
evidence: docs/flex-auth-integration.md
notes: >-
The check is a service-identity question (who may call this PIP), not
a tenant-capability-role question. flex-auth's tenant-engine policy
package matches subject id and action only and does not consult
tenant_roles. Its live-roles adapter is built and unwired. Therefore
GET /roles/live → POST /v1/check does not re-enter this engine.