---
id: ATS-PFM-SEC-007
scope: CAP-PFM-SEC-007
product_area: platform
module: security
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-SEC-007-01
    title: Caller identity and no-store responses
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-01
    preconditions: Prepare two users and a suspended membership.
    steps: Request context as each user and without authentication.
    expected: >-
      Each active caller receives their own identity; suspended and anonymous requests fail, and
      responses include no-store guidance.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the user
        the signed context names and no other, so one person can never read another’s document
      - TST-PFM-SEC-065
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#refuses a
        suspended user, whose slice carries no grant of reading themselves at all
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#tells every cache
        not to keep a document about who the caller is
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#refuses an
        anonymous caller, and says so with the header still on the refusal
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the user the
      signed context names and no other, so one person can never read another’s document
    category: permission
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the user
        the signed context names and no other, so one person can never read another’s document
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#refuses a
        suspended user, whose slice carries no grant of reading themselves at all
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#tells every cache
        not to keep a document about who the caller is
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#refuses an
        anonymous caller, and says so with the header still on the refusal
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the user
        the signed context names and no other, so one person can never read another’s document
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the user
        the signed context names and no other, so one person can never read another’s document
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-02
    title: No-access handling for ineffective grants
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-02
    preconditions: 'Prepare users with no assignment, pending assignment and future-only assignment.'
    steps: 'Request context, then add or activate an applicable grant.'
    expected: Ineffective grants produce the no-access refusal and screen; a current grant permits context.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        refused their own document rather than answered an empty one
      - TST-PFM-SEC-182
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        refused, because a grant nobody has accepted is a grant nobody holds
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        answered the document once the window has opened
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#is refused 403
        under the code the console reads as no access
      - TST-PFM-SEC-065
      - >-
        react-console:e2e/dev/permissions.dev.spec.ts#shows a person with no role the No Access
        screen, and does not loop back to the login screen
      - TST-PFM-SEC-015
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
      refused their own document rather than answered an empty one
    category: edge
    test_references:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        refused their own document rather than answered an empty one
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        refused, because a grant nobody has accepted is a grant nobody holds
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        answered the document once the window has opened
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#is refused 403
        under the code the console reads as no access
      - >-
        react-console:e2e/dev/permissions.dev.spec.ts#shows a person with no role the No Access
        screen, and does not loop back to the login screen
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        refused their own document rather than answered an empty one
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#is
        refused their own document rather than answered an empty one
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-03
    title: Effective permission expansion and denies
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-03
    preconditions: Prepare a Read Only member with a deny and another member with a custom role.
    steps: Read both contexts.
    expected: >-
      The first receives allowed read keys except the denied key; the second receives the custom
      role’s allowed key.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers every key
        the database says Read Only allows, not only the key the signed slice was resolved for
      - TST-PFM-SEC-065
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#takes
        the denied key out of the allowed keys, though another grant allows it
      - TST-PFM-SEC-182
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#allows
        the one key the custom role names, and no key of any built-in
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers every key
      the database says Read Only allows, not only the key the signed slice was resolved for
    category: rule
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers every key
        the database says Read Only allows, not only the key the signed slice was resolved for
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#takes
        the denied key out of the allowed keys, though another grant allows it
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#allows
        the one key the custom role names, and no key of any built-in
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers every key
        the database says Read Only allows, not only the key the signed slice was resolved for
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers every key
        the database says Read Only allows, not only the key the signed slice was resolved for
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-04
    title: Separation of HQ and workspace authority
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-04
    preconditions: Prepare a Rhythm Administrator with a platform-scope grant.
    steps: Read the staff member’s context.
    expected: >-
      HQ contains staff permissions, while that platform grant contributes no customer-console
      permission.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
        the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one included
      - TST-PFM-SEC-182
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#allows
        the same person nothing on a console route, because a platform-scope grant counts on
        `system` alone
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
      the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one included
    category: boundary
    test_references:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
        the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one included
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#allows
        the same person nothing on a console route, because a platform-scope grant counts on
        `system` alone
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
        the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one included
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
        the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one included
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-05
    title: Unavailable workspace selection
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-05
    preconditions: Prepare a customer with a workspace still provisioning.
    steps: >-
      Read ordinary context and request the provisioning workspace strictly as its user and as staff
      without an applicable customer-access grant.
    expected: >-
      The workspace is not offered or selected as default; strict selection fails for the tested
      callers.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#offers
        the customer’s own person only the tenants they can work in
      - TST-PFM-SEC-182
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#never
        starts the session in it
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#refuses
        Rhythm staff it by path, because staff enter another customer’s tenant only through a grant
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#offers
      the customer’s own person only the tenants they can work in
    category: boundary
    test_references:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#offers
        the customer’s own person only the tenants they can work in
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#never
        starts the session in it
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#refuses
        Rhythm staff it by path, because staff enter another customer’s tenant only through a grant
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#offers
        the customer’s own person only the tenants they can work in
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#offers
        the customer’s own person only the tenants they can work in
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-06
    title: Strict and preferred workspace parameters
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-06
    preconditions: 'Prepare reachable, unreachable and missing identifiers.'
    steps: >-
      Request each strictly, try an unreachable preference and combine strict and preferred
      parameters.
    expected: >-
      Results are 200, access-denied 403 and not-found 404; preference falls back and the
      conflicting parameters return 400.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#evaluates the
        tenant the query names, when the caller reaches it
      - TST-PFM-SEC-065
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#refuses the same
        tenant named strictly by tenant_id, the console URL never falling back
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#ignores a
        preferred tenant out of the caller's reach rather than refusing it
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers 404 tenant_not_found
        for ?tenant_id=nobody.org
      - TST-PFM-SEC-230
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#evaluates the tenant
      the query names, when the caller reaches it
    category: validation
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#evaluates the
        tenant the query names, when the caller reaches it
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#refuses the same
        tenant named strictly by tenant_id, the console URL never falling back
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#ignores a
        preferred tenant out of the caller's reach rather than refusing it
      - >-
        services-platform:modules/tenants/tests/e2e/tenants.e2e.spec.js#answers 404 tenant_not_found
        for ?tenant_id=nobody.org
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#evaluates the
        tenant the query names, when the caller reaches it
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#evaluates the
        tenant the query names, when the caller reaches it
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-07
    title: Application access and licence gates
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-07
    preconditions: Prepare missing licensing and an application-access deny.
    steps: Inspect context and call application routes.
    expected: >-
      Unavailable applications are absent and refused, while exempt Platform routes remain available
      subject to their own authorization.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the
        application that follows from those keys
      - TST-PFM-SEC-065
      - >-
        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
      - TST-PFM-SEC-047
      - >-
        services-platform:modules/security/tests/e2e/application-access-enforced.e2e.spec.js#serves
        a Platform route in the withheld tenant, because Platform is exempt from the licence step
      - >-
        react-console:e2e/mock/application-access.mock.spec.ts#an application the organization does
        not have is absent from the sidebar
      - TST-PFM-SEC-020
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the
      application that follows from those keys
    category: permission
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the
        application that follows from those keys
      - >-
        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
      - >-
        services-platform:modules/security/tests/e2e/application-access-enforced.e2e.spec.js#serves
        a Platform route in the withheld tenant, because Platform is exempt from the licence step
      - >-
        react-console:e2e/mock/application-access.mock.spec.ts#an application the organization does
        not have is absent from the sidebar
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the
        application that follows from those keys
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/security-context.e2e.spec.js#answers the
        application that follows from those keys
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-08
    title: Context loading and recovery before console work
    level: browser
    proves:
      - BR-CAP-PFM-SEC-007-08
    preconditions: Arrange a context failure and an expired token.
    steps: Open the console and use retry after failure.
    expected: >-
      Application content waits for context; retry opens it, and token renewal can proceed without
      another user sign-in.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
        when the Platform cannot say what somebody may do, and opens it on the retry
      - TST-PFM-SEC-006
      - >-
        react-console:e2e/controlled/security-context.controlled.spec.ts#refreshes and retries by
        itself when the access token has aged out
    provenance: test
    source: >-
      react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
      when the Platform cannot say what somebody may do, and opens it on the retry
    category: failure
    test_references:
      - >-
        react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
        when the Platform cannot say what somebody may do, and opens it on the retry
      - >-
        react-console:e2e/controlled/security-context.controlled.spec.ts#refreshes and retries by
        itself when the access token has aged out
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
        when the Platform cannot say what somebody may do, and opens it on the retry
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
        when the Platform cannot say what somebody may do, and opens it on the retry
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-09
    title: Actions and deep links against console permissions
    level: browser
    proves:
      - BR-CAP-PFM-SEC-007-09
    preconditions: Prepare administrator and read-only sessions.
    steps: Compare available actions and enter a page address that lacks the required permission.
    expected: >-
      The read-only session omits the unavailable action and the protected deep link displays access
      denial.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        react-console:e2e/dev/permissions.dev.spec.ts#offers the administrator an action it does not
        offer the read-only user
      - TST-PFM-SEC-015
      - >-
        react-console:e2e/dev/permissions.dev.spec.ts#denies a page whose permission nobody holds,
        when its URL is typed
      - >-
        react-console:e2e/security/access.spec.ts#lets somebody into the console and still refuses
        them the Security screens
      - TST-PFM-SEC-030
    provenance: test
    source: >-
      react-console:e2e/dev/permissions.dev.spec.ts#offers the administrator an action it does not
      offer the read-only user
    category: permission
    test_references:
      - >-
        react-console:e2e/dev/permissions.dev.spec.ts#offers the administrator an action it does not
        offer the read-only user
      - >-
        react-console:e2e/dev/permissions.dev.spec.ts#denies a page whose permission nobody holds,
        when its URL is typed
      - >-
        react-console:e2e/security/access.spec.ts#lets somebody into the console and still refuses
        them the Security screens
    action_evidence:
      provenance: test
      source: >-
        react-console:e2e/dev/permissions.dev.spec.ts#offers the administrator an action it does not
        offer the read-only user
    assertion_evidence:
      provenance: test
      source: >-
        react-console:e2e/dev/permissions.dev.spec.ts#offers the administrator an action it does not
        offer the read-only user
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-10
    title: Pending and revoked assignments in the access document
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-10
      - INV-DOM-PFM-SEC-003-08
    preconditions: Prepare pending-only and revoked-grant members.
    steps: Read their access documents.
    expected: Pending assignments appear without permission; revoked assignments are absent.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/access.e2e.spec.js#answers a caller whose only
        grant is pending with a document allowing nothing, rather than refusing them
      - TST-PFM-SEC-046
      - >-
        services-platform:modules/security/tests/e2e/access.e2e.spec.js#leaves a member's revoked
        grant out of the document, and allows nothing on the strength of a slice alone
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/access.e2e.spec.js#answers a caller whose only
      grant is pending with a document allowing nothing, rather than refusing them
    category: transition
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/access.e2e.spec.js#answers a caller whose only
        grant is pending with a document allowing nothing, rather than refusing them
      - >-
        services-platform:modules/security/tests/e2e/access.e2e.spec.js#leaves a member's revoked
        grant out of the document, and allows nothing on the strength of a slice alone
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/access.e2e.spec.js#answers a caller whose only
        grant is pending with a document allowing nothing, rather than refusing them
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/access.e2e.spec.js#answers a caller whose only
        grant is pending with a document allowing nothing, rather than refusing them
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-11
    title: Name-lookup limits and disclosure
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-11
    preconditions: Prepare identities from two customers and Rhythm staff.
    steps: 'Request 101 and 100 identities, include another customer’s user and call as a portal member.'
    expected: >-
      The excessive request returns 400, valid permitted identities return only the presentation
      fields, outside identities are omitted and the portal caller receives 403.
    negative: true
    data_needs: Use the records described in the setup.
    bound_to:
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#leaves out another
        customer's user and an id that names nobody, rather than nulling or refusing them
      - TST-PFM-SEC-068
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#carries the id, the
        display name and the avatar of each person, and nothing else about anybody
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#refuses a request naming
        more than the hundred people it takes, rather than answering the first of them
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#is refused by the access
        tier, because the route is console
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#leaves out another
      customer's user and an id that names nobody, rather than nulling or refusing them
    category: boundary
    test_references:
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#leaves out another
        customer's user and an id that names nobody, rather than nulling or refusing them
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#carries the id, the
        display name and the avatar of each person, and nothing else about anybody
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#refuses a request naming
        more than the hundred people it takes, rather than answering the first of them
      - >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#is refused by the access
        tier, because the route is console
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#leaves out another
        customer's user and an id that names nobody, rather than nulling or refusing them
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/e2e/user-names.e2e.spec.js#leaves out another
        customer's user and an id that names nobody, rather than nulling or refusing them
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-12
    title: Console access after a role change
    level: browser
    proves:
      - AS-JNY-PFM-SEC-002-03
    preconditions: Prepare a member holding a role.
    steps: 'Sign in, change the role and request fresh context.'
    expected: >-
      Fresh context and its resulting console presentation reflect the changed grant; this does not
      establish immediate eviction of every cached request decision.
    negative: false
    data_needs: Use the records described in the setup.
    bound_to:
      - 'react-console:e2e/security/access.spec.ts#a role change alters what somebody can actually do'
      - TST-PFM-SEC-030
    provenance: test
    source: 'react-console:e2e/security/access.spec.ts#a role change alters what somebody can actually do'
    category: interaction
    test_references:
      - 'react-console:e2e/security/access.spec.ts#a role change alters what somebody can actually do'
    action_evidence:
      provenance: test
      source: 'react-console:e2e/security/access.spec.ts#a role change alters what somebody can actually do'
    assertion_evidence:
      provenance: test
      source: 'react-console:e2e/security/access.spec.ts#a role change alters what somebody can actually do'
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-13
    title: Authentication bookkeeping during context reads
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-13
    preconditions: Prepare an active member with effective access and a controlled execution clock.
    steps: >-
      Build context, repeat within a minute and after it; call bookkeeping as a job and with a
      failing database.
    expected: >-
      Authentication time is throttled while status and version stay fixed; the job does not stamp,
      and stamp failure is logged without propagating.
    negative: false
    data_needs: 'Use an active member, fixed clock and database failure fixture.'
    bound_to:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#records
        the instant the document was built, and leaves the status and the version where they were
      - TST-PFM-SEC-182
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#does
        not write again on a second read in the same minute
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#writes
        again once a minute has passed, so the column still says when the person was last here
      - >-
        services-platform:modules/security/tests/unit/services/access/security-context.spec.ts#answers
        rather than raising when the stamp cannot be written, and says in the log which user it was
        about
      - TST-PFM-SEC-199
      - >-
        services-platform:modules/security/tests/unit/services/access/security-context.spec.ts#writes
        nothing for an unattended job acting for the person, the report renderer’s boot call (the
        case above is its control)
    provenance: test
    source: >-
      services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#records
      the instant the document was built, and leaves the status and the version where they were
    category: edge
    test_references:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#records
        the instant the document was built, and leaves the status and the version where they were
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#does
        not write again on a second read in the same minute
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#writes
        again once a minute has passed, so the column still says when the person was last here
      - >-
        services-platform:modules/security/tests/unit/services/access/security-context.spec.ts#answers
        rather than raising when the stamp cannot be written, and says in the log which user it was
        about
      - >-
        services-platform:modules/security/tests/unit/services/access/security-context.spec.ts#writes
        nothing for an unattended job acting for the person, the report renderer’s boot call (the
        case above is its control)
    action_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#records
        the instant the document was built, and leaves the status and the version where they were
    assertion_evidence:
      provenance: test
      source: >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#records
        the instant the document was built, and leaves the status and the version where they were
    binding_scope: >-
      The binding applies to the cited executable observations and their dependency boundary. Extra
      setup, operations or combinations in this scenario still require evidence before the whole
      scenario is qualified.
  - id: ATS-PFM-SEC-007-14
    title: Understand available workspace access with use and recover a console sign-in
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-006-03
      - BR-CAP-PFM-SEC-007-08
    exercises:
      - CAP-PFM-SEC-007
      - CAP-PFM-SEC-006
    preconditions: A signed-in person has an in-force workspace assignment.
    steps: >-
      Reload the browser, wait for context, and then repeat with a person whose assignments are
      ineffective.
    expected: >-
      Restoration admits protected content only after context succeeds; the second person receives
      No Access.
    negative: false
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - >-
        react-console:lib/auth/__tests__/session.test.ts#keeps the access token in memory and the
        refresh token nowhere
      - >-
        react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
        when the Platform cannot say what somebody may do, and opens it on the retry
    action_evidence:
      provenance: proposed
      source:
        - >-
          react-console:lib/auth/__tests__/session.test.ts#keeps the access token in memory and the
          refresh token nowhere
        - >-
          react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
          when the Platform cannot say what somebody may do, and opens it on the retry
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          react-console:lib/auth/__tests__/session.test.ts#keeps the access token in memory and the
          refresh token nowhere
        - >-
          react-console:e2e/controlled/security-context.controlled.spec.ts#will not open the console
          when the Platform cannot say what somebody may do, and opens it on the retry
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-007-15
    title: Understand available workspace access with assign roles within a controlled scope
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-12
      - BR-CAP-PFM-SEC-010-07
    exercises:
      - CAP-PFM-SEC-007
      - CAP-PFM-SEC-010
    preconditions: A member holds a role granting access to one security area.
    steps: 'Withdraw the assignment, wait out the gateway cache, and reload access and the protected page.'
    expected: Fresh context omits the permission and the protected page is refused.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - >-
        react-console:e2e/controlled/tenant-unavailable.controlled.spec.ts#falls back to the default
        tenant, with a word of explanation, rather than refusing access
      - >-
        services-platform:modules/security/tests/integration/services/membership/manage-assignments.integration.spec.js#revokes
        the grant, keeps the row, and audits what was withdrawn
    action_evidence:
      provenance: proposed
      source:
        - >-
          react-console:e2e/controlled/tenant-unavailable.controlled.spec.ts#falls back to the
          default tenant, with a word of explanation, rather than refusing access
        - >-
          services-platform:modules/security/tests/integration/services/membership/manage-assignments.integration.spec.js#revokes
          the grant, keeps the row, and audits what was withdrawn
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          react-console:e2e/controlled/tenant-unavailable.controlled.spec.ts#falls back to the
          default tenant, with a word of explanation, rather than refusing access
        - >-
          services-platform:modules/security/tests/integration/services/membership/manage-assignments.integration.spec.js#revokes
          the grant, keeps the row, and audits what was withdrawn
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
  - id: ATS-PFM-SEC-007-16
    title: Understand available workspace access with control staff access to customer workspaces
    category: interaction
    level: api
    proves:
      - BR-CAP-PFM-SEC-007-04
      - BR-CAP-PFM-SEC-017-06
    exercises:
      - CAP-PFM-SEC-007
      - CAP-PFM-SEC-017
    preconditions: A staff member has approved entry to one customer workspace.
    steps: >-
      Read HQ and workspace contexts, revoke the entry, and read again after cached authority
      expires.
    expected: HQ authority remains separate; the customer workspace is unavailable after revocation.
    negative: true
    data_needs: >-
      An isolated customer with two workspaces, ordinary and staff identities, and records owned by
      this run.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
        the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one included
      - >-
        services-platform:modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js#leaves
        that standing grant revoked when standing access is ensured again
    action_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
          the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one
          included
        - >-
          services-platform:modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js#leaves
          that standing grant revoked when standing access is ensured again
    assertion_evidence:
      provenance: proposed
      source:
        - >-
          services-platform:modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js#expands
          the wildcard to every concrete key of the catalog in Rhythm HQ, the staff-only one
          included
        - >-
          services-platform:modules/security/tests/integration/services/staff-access/approved-tenant-access.integration.spec.js#leaves
          that standing grant revoked when standing access is ensured again
    binding_scope: >-
      No executable assertion is bound. The scenario specifies proposed proof and does not establish
      implemented or passing behavior.
evidence:
  - >-
    Pinned services-platform references for the structured rows:
    modules/security/tests/e2e/access.e2e.spec.js;
    modules/security/tests/e2e/application-access-enforced.e2e.spec.js;
    modules/security/tests/e2e/security-context.e2e.spec.js;
    modules/security/tests/e2e/user-names.e2e.spec.js;
    modules/security/tests/integration/services/security-context/get-security-context.integration.spec.js;
    modules/security/tests/unit/services/access/security-context.spec.ts;
    modules/tenants/tests/e2e/tenants.e2e.spec.js.
  - >-
    Pinned react-console references for the structured rows:
    e2e/controlled/security-context.controlled.spec.ts; e2e/dev/permissions.dev.spec.ts;
    e2e/mock/application-access.mock.spec.ts; e2e/security/access.spec.ts.
  - >-
    Testing back-fill reviews the pinned suite assertions, related capabilities, domain invariants,
    state transitions and workflow failure boundaries. New unbound rows remain proposed.
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: covered
  boundary: covered
  concurrency: 'gap: FND-PFM-SEC-064'
  invariant: 'gap: FND-PFM-SEC-064'
  interaction: covered
coverage_notes:
  concurrency: No scenario isolates this category. The referenced finding retains the missing design proof.
  invariant: No scenario isolates this category. The referenced finding retains the missing design proof.
invariant_proofs:
  - scenario: ATS-PFM-SEC-007-10
    proves:
      - INV-DOM-PFM-SEC-003-08
    provenance: test
    source: >-
      services-platform:modules/security/tests/e2e/access.e2e.spec.js#answers a caller whose only
      grant is pending with a document allowing nothing, rather than refusing them
    proof_scope: >-
      Only the cited assertions support this invariant mapping; a source reference does not
      establish a passing execution.
permission_proof_review:
  - key: platform.security-self.read
    scenario_candidates:
      - ATS-PFM-SEC-007-01
      - ATS-PFM-SEC-007-09
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-064
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-007-know-what-i-may-do-in-a-workspace.md
  - key: platform.application.access
    scenario_candidates:
      - ATS-PFM-SEC-007-01
      - ATS-PFM-SEC-007-09
    qualification: >-
      These are candidate scenarios for the authority boundary, not an exhaustive allowed/refused
      matrix for this key. The finding retains combinations not established by the executable
      assertions.
    gap: FND-PFM-SEC-064
    provenance: inferred
    source: >-
      specs/platform/security/planning/capabilities/CAP-PFM-SEC-007-know-what-i-may-do-in-a-workspace.md
examiner: codex
examined_at: '2026-10-23'
final_text: OpenAI
---
# Understand available workspace access: Capability Test Specification

## Coverage

| Required rule | Scenario or finding |
|---|---|
| `BR-CAP-PFM-SEC-007-01` | `ATS-PFM-SEC-007-01` |
| `BR-CAP-PFM-SEC-007-02` | `ATS-PFM-SEC-007-02` |
| `BR-CAP-PFM-SEC-007-03` | `ATS-PFM-SEC-007-03` |
| `BR-CAP-PFM-SEC-007-04` | `ATS-PFM-SEC-007-04`, `ATS-PFM-SEC-007-16` |
| `BR-CAP-PFM-SEC-007-05` | `ATS-PFM-SEC-007-05` |
| `BR-CAP-PFM-SEC-007-06` | `ATS-PFM-SEC-007-06` |
| `BR-CAP-PFM-SEC-007-07` | `ATS-PFM-SEC-007-07` |
| `BR-CAP-PFM-SEC-007-08` | `ATS-PFM-SEC-007-08`, `ATS-PFM-SEC-007-14` |
| `BR-CAP-PFM-SEC-007-09` | `ATS-PFM-SEC-007-09` |
| `BR-CAP-PFM-SEC-007-10` | `ATS-PFM-SEC-007-10` |
| `BR-CAP-PFM-SEC-007-11` | `ATS-PFM-SEC-007-11` |
| `BR-CAP-PFM-SEC-007-13` | `ATS-PFM-SEC-007-13` |

The category map records specified proof. A covered category can contain proposed scenarios; it does not mean the checks have run. The bindings identify individual executable contributions, while findings retain missing rules, permissions, transitions and assertions.

## Interactions With Related Capabilities

The interaction scenarios connect this capability to the related actions and workflow handoffs named in their proof references. Each case observes the outcome after the connected action changes records or available authority. A collection of separately bound checks does not establish an ordered feature journey.

Source revisions and assertion references are recorded in frontmatter. Steps and expected observations carry separate evidence annotations. Proposed checks remain distinct from executable test statements, and static review supplies no run result.
