Skip to content

CAP-PFM-SEC-015Enforce access at request boundaries

Markdown

CAP-PFM-SEC-015

Enforce access at request boundaries

Markdown
  • DocumentDraft
  • Product intentConfirmed
  • ImplementationObserved

KindCapabilityProduct areaPlatformModuleSecurity, Customers and WorkspacesRevision1

Read atservices-platform ad3f6a65

The Formal Contract

The narrative above explains; the sections below are authoritative — the rules, scenarios and tests this document binds.

Outcomes
Protected person requests receive a bounded authorization decision.Staff and customer authority remain distinct at request boundaries.Refusal metadata explains the required access without caller identity data.
Surfaces
api
Intent sources
services-platform:docs/hq/rhythm-hq-plan.md#D1 (rule S1, accepted 2026-10-12)services-platform:docs/security/application-access.md#The application access step, enforced everywhereservices-platform:docs/security/grant-slice-growth.md#Andrew's decisions (2026-10-19, Decision 1: A)services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11 Final acceptance)

Controls

41 controls apply, from the corpus control catalogue.

TC-AVL-001 TC-AVL-004 TC-AZ-001 TC-AZ-002 TC-AZ-003 TC-AZ-004 TC-AZ-005 TC-AZ-006 TC-CRY-001 TC-CRY-002 TC-CRY-003 TC-CRY-004 TC-DAT-001 TC-DAT-002 TC-DAT-003 TC-IAM-001 TC-IAM-002 TC-IAM-003 TC-IAM-004 TC-IAM-005 TC-IAM-006 TC-LOG-001 TC-LOG-004 TC-LOG-005 TC-MON-001 TC-PI-001 TC-PI-002 TC-PI-004 TC-PI-005 TC-PRV-001 TC-PRV-002 TC-SEC-001 TC-SEC-002 TC-SEC-003 TC-SEC-004 TC-TEN-001 TC-TEN-002 TC-TEN-003 TC-VEN-001 TC-VEN-002 TC-VEN-003

Permissions

KeyChecked atScope
platform.application.accessapitenant
platform.security-self.readapirecord

Business Rules

13 rules, 11 to be proved before approval. A rule's product intent is derived from its origin: 13 confirmed by a product decision, the rest inheriting this capability's confirmed.

IdRuleKindEnforced atProvenance
01must prove
Confirmed
A protected request requires a token issued through an active registered pool and client. Missing tokens, unknown issuers, inactive pools and unregistered clients are rejected before identity or grant lookup.
origin: services-platform:docs/security/console-authentication.md#Acceptance checkpoints (2026-10-10 Final acceptance)
validationapitest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#refuses an unknown issuer: 401, and no pool, identity or grant is read
02must prove
Confirmed
Authorization uses an existing identity belonging to an active user in the pool’s account boundary. It creates no identity; suspended, invited and revoked users cannot proceed.
origin: services-platform:docs/security/console-authentication.md#Acceptance checkpoints (2026-10-10 Final acceptance)
validationapitest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#refuses an unknown identity with 401 and writes nothing: the authorizer never creates one
03must prove
Confirmed
Portal tokens cannot authorize console or HQ routes. Portal membership applies only in its own workspace; ordinary console membership does not cross the customer boundary.
origin: services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11 Final acceptance)
permissionapitest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#refuses a portal token on a console route before any identity is read
04must prove
Confirmed
Staff authority applies to HQ routes. Even the broadest staff grant supplies no console or portal authority, and customer Administrator authority supplies no staff status on HQ routes.
origin: services-platform:docs/hq/rhythm-hq-plan.md#D1 (rule S1, accepted 2026-10-12)
permissionapi, servicetest
services-platform:modules/security/tests/e2e/staff-separation.e2e.spec.js#refuses the widest grant Rhythm holds, every one of them
05must prove
Confirmed
A release must declare each served operation. System routes require staff-only keys, staff-only keys belong on system routes, and protected routes require permissions. Invalid declarations prevent staging.
origin: services-platform:docs/hq/rhythm-hq-plan.md#D1 (rule S1, accepted 2026-10-12)
validationservicetest
06must prove
Confirmed
Authorization limits the request to workspaces reachable through applicable grants. An inaccessible workspace in the path is refused; an operation with no applicable grant is denied altogether.
origin: services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11 Final acceptance)
permissionapitest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#returns a Deny for the whole route when no grant could apply anywhere
07must prove
Confirmed
The service receives authority through a signed context rather than the raw token. Its expiry follows the gateway cache lifetime plus thirty seconds, and it contains no caller address. A grant slice exceeding 6 KB, or failure to read the registry, grants or signing key, prevents authorization.
origin: services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-11 Final acceptance)
invariantapitest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#refuses a grant slice over 6 KB rather than truncating it
08must prove
Confirmed
Refusal metadata describes the cause and required permission keys without identifying the caller or another person.
policyapitest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#names the refusal reason and the missing key, both strings, and nothing that identifies the caller
09must prove
Confirmed
Application permissions require both an application-access grant and a workspace licence. These checks enforce in every environment; Platform and HQ are exempt. Refusals provide client-readable codes.
origin: services-platform:docs/security/application-access.md#The application access step, enforced everywhere
permissionservicetest
services-platform:modules/security/tests/e2e/application-access-enforced.e2e.spec.js#is refused it once a deny names the access key, though the allow beside it is untouched
10
Confirmed
Where a service enables decisions by workspace path, the cached decision and grant slice cover that workspace alone, avoiding growth with the customer’s workspace count.
origin: services-platform:docs/security/grant-slice-growth.md#Andrew's decisions (2026-10-19, Decision 1: A)
policyapitest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#decides and signs for the path workspace alone: the policy, the tenants and the slice name no other
11must prove
Confirmed
Access changes can leave an existing gateway decision usable for at most its sixty-second cache lifetime. The flush workflow can report success without evicting that decision.
origin: services-platform:docs/security/security-administration.md#14 Acceptance checkpoints (2026-10-12/13, known bound accepted 2026-10-13)
policyapidocumented
12
Confirmed
A record-type grant can permit passage through the gateway; the resource service must still answer an unrelated record type as not found.
origin: services-platform:docs/security/security-administration.md#12. Approved omissions and tracked gaps (resource-scoped grants, PLAT-M5 D10)
permissionapi, servicetest
services-platform:modules/security/tests/unit/authorizer/authorize.spec.ts#the gateway lets the holder through to an object the scope does not name, so the service answers it as not found
13must prove
Confirmed
Service-to-service authority comes from the calling service’s cloud role. A service function must declare the operation it serves, and a sensitive operation requires a function marked sensitive.
origin: services-platform:docs/security/service-calls.md#Service calls: the service-principal registry and the kill switch
permissionservicetest
services-platform:modules/security/tests/unit/authorizer/service-function-rules.spec.ts#refuses a route whose catalog permission is sensitive behind a function that is not, naming the key

Scenarios

IdGivenWhenThenProvenance
01A person holds the complete HQ Administrator grant.They request a CRM contact route without customer access.HQ authority does not authorize the CRM request; a separate staff access grant is needed.test
services-platform:modules/security/tests/e2e/staff-separation.e2e.spec.js#refuses a route that names a tenant at the boundary, because reaching every tenant is a system claim too
02A workspace lacks an application licence.A permission holder requests that application and then Platform.The application request returns a licensing refusal; the Platform request remains available.test
services-platform:modules/security/tests/e2e/application-access-enforced.e2e.spec.js#refuses the same route in the withheld tenant, under the licence step’s own code

The Markdown files under specs/ in rhythmsoftware/rhythm-v2-docs are the canonical source of truth. This reader is a generated, read-only projection of them.