From b55d724e7763001ed6f925d760c3f013556bdea5 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Mon, 7 Sep 2026 23:30:27 +0100 Subject: [PATCH 1/6] docs: bound admin access audit around real lifecycle proof --- .../initiatives/WS-QUAL-003/WS-QUAL-003-13.md | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 .commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md diff --git a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md new file mode 100644 index 000000000..eaef3cde7 --- /dev/null +++ b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md @@ -0,0 +1,206 @@ +# WS-QUAL-003-13 — Admin access lifecycle proof audit + +- Initiative: WS-QUAL-003 +- Durable disposition: Planned +- Intended merge outcome: Eight mixed bootstrap/admin-access tests become + bounded behavior proofs with a retained signed-token API journey and exact + PostgreSQL concurrency/rollback custody. + +## Intent + +Continue the behavior-first audit without treating test count or coverage as +the goal. The human asked to compare unit and end-to-end proof: keep a small +representative connected journey, use PostgreSQL for persistence/transaction +claims, and use focused tests for independent variations. This is one PR with +reviewed commits, not a separate planning PR followed by tiny cleanup PRs. + +## Current behavior + +Baseline is main `0e34911be4cdc25b3ec79dbcb097b62181958304` (PR379). +`backend/tests/test_auth.py` retains 23 named tests. Eight selected tests occupy +the bootstrap/admin-access family; fifteen other test bodies remain unchanged. +The 1,040-line `test_signed_tokens_bootstrap_and_admin_grant_lifecycle` mixes +signed-token admission, bootstrap, reads, concealment, fault injection, grant +issue/revoke, scope and replay. Its final event totals depend on the entire +history instead of identifying each mutation's effects. + +`test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe` combines +bootstrap, timestamp ordering, same-key recovery, distinct-key duplication, +cross-revocation and both revoke-versus-issue orders. Several barriers establish +arrival but do not observe the actual database wait. The separate admin-read +race checks any blocker of the transition PID, not the exact reader PID; it +resets shared lifecycle rows between cases with disabled user triggers. + +Production owners are `scripts/bootstrap_access_administrator.py`, +`authorization/admin_service.py`, `authorization/repository.py`, shared +authority mutation/PREP and route composition, plus ACTORS read/touch owners. +The canonical specification is `docs/spec_authorization_service.md`, especially +Bootstrap And Final-Administrator Safety. Bootstrap takes the control-row lock, +validates an active human/link, and atomically stages grant/control/event. +Later attempts produce audited conflicts; ordinary token role claims do not +grant Workstream administrator authority. + +These are observed proof weaknesses, not established production defects. + +## Bounded change + +### Allowed + +- This record and `WS-QUAL-003/OVERVIEW.md` for durable audit disposition. +- `backend/tests/test_auth.py`: remove only the eight named tests below, move + its exact `auth_database_env` fixture to shared non-test support, re-import + it for unchanged consumers, and remove only demonstrably dead imports. +- `backend/tests/authentication/fixtures.py`: own the unchanged database fixture. +- New `backend/tests/authorization/admin_access/` package with `__init__.py`, + `conftest.py`, `support.py`, `fixtures.py`, `fault_support.py`, + `concurrency_support.py`, `read_support.py` and the test files below. + Split support further only by a named behavior and record the scope correction + before implementation; no arbitrary helper framework. +- `.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json` and new assertion map + `.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json`: reconcile actual + inventory without new/grown or rewritten-same-size debt. +- `backend/scripts/test_lane_catalogue.py` and + `backend/tests/test_ci_lane_catalogue.py`: register moved tests in existing + lanes and prove no omission. Preserve unrelated product registrations. + +### Not allowed + +No production, migration, public contract, runtime authority, workflow, +threshold, timeout, dependency, or feature change. No whole-suite local run or +local PostgreSQL execution. No deletion justified by line count or coverage. +No edits to the product worktree. No re-audit of completed PR379 families. +Do not rewrite the other fifteen authentication tests or the 163-test AUTH +monolith. Read them as possible survivors, not editable scope. + +## Design and decisions + +Inventory every original assertion and materially distinct loop/parameter case +before removal. Map it to a surviving named assertion, or explain its redundant +protection and stronger existing owner test. Hashes demonstrate custody, not +semantic equivalence. No deletion decision is pre-approved by this plan. + +Keep a short signed-token → first access → local bootstrap → grant → observed +role → revoke → observed role-removal journey through ASGI and real PostgreSQL. +Call it API composition, not deployed-network/worker E2E. Use strict reusable +setup for the other tests instead of replaying every previous behavior. Setup +must use real owners or valid fresh rows and must fail promptly on invalid +preconditions. Faults are test-local and installed only after setup. + +Keep each new file below 500 lines, tests at most 120 and helpers at most 100. +Do not hide the old 1,040-line scenario in a helper. Separate meaningful failure +cases; do not multiply equivalent parameter combinations for coverage. + +Reuse `auth_concurrency_support.wait_for_named_database_lock` with exact waiter +and blocker PIDs. Capture session PIDs before each claimed lock; retain the real +owner call. Hold the winner until the observer proves the contention. A waiter +that finishes early is failure, not success. Each harness owns cancellation, +task joining and hook restoration in `finally`; the observer uses its existing +fresh AUTOCOMMIT connection. No sleep is proof of serialization. + +Give each admin-read lifecycle case fresh valid identities/grants. The actual +profile/link transition may use direct SQL as the existing lock test does, but +keep triggers enabled; it proves read/row-lock protection, not lifecycle API +orchestration. Grant revocation keeps the real HTTP command. Do not disable +triggers to restore shared fixtures between cases. + +For commit-failure tests, inspect actual staged grant/state and audit effects +before raising, then inspect fresh-session state after rollback. Assert issue, +revoke and read failures independently; evidence-denial tests must identify +whether the fault happens before staging or after it. Scope event assertions +by exact operation/resource and link success to invalidation, not global totals. +Keep response concealment assertions independent of internal evidence assertions. + +## Source selection and destinations + +All sources below are the exact functions in baseline `backend/tests/test_auth.py`. +Destination paths below are relative to `tests/authorization/admin_access/`. + +| Original function | Disposition / destination | +|---|---| +| `test_signed_tokens_bootstrap_and_admin_grant_lifecycle` | Audit all assertions; retain representative `test_api_journey.py`; separate `test_bootstrap_postgresql.py`, `test_admin_reads_postgresql.py`, `test_grant_api_postgresql.py`, `test_failure_atomicity_postgresql.py` | +| `test_bootstrap_command_manifest_matches_the_active_catalogue` | Retain exact principal/action/permission proof in `test_bootstrap_cli.py` | +| `test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails` | Retain command-output proof; strengthen exact actor forwarding and cleanup custody | +| `test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request` | Retain private infrastructure-failure mapping | +| `test_bootstrap_cli_rejects_arguments_without_echoing_them` | Retain distinct malformed arguments; assert neither stdout nor stderr leaks supplied data and execution is not entered | +| `test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure` | Split interrupt from infrastructure/cleanup failure into independent command cases | +| `test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe` | Split `test_grant_concurrency_postgresql.py` and `test_timestamp_concurrency_postgresql.py`; preserve each distinct operation/order and replace arrival-only claims with exact custody | +| `test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure` | `test_read_concurrency_postgresql.py`; retain profile/link × suspend/deactivate/link-revoke/grant-revoke cases with exact blocker, independent fresh setup and denied subsequent disclosure | + +## Acceptance criteria and named future proof + +Every row is a future proof requirement, not an executed result. All database, +API and concurrency tests below run in hosted CI only; command tests are local. +Parameter cases must remain independently identifiable in final assertion map. + +| Behavior | Future proof name | Required observation | +|---|---|---| +| Connected signed authentication and grant lifecycle | `test_signed_admin_grant_journey` | Real verifier, API, PostgreSQL; target role appears then disappears after revoke | +| External role does not bootstrap authority | `test_token_role_cannot_read_authorization_catalogue` | Valid signed token with elevated role claim, denied protected read | +| Dry run is non-mutating | `test_bootstrap_dry_run_leaves_control_grants_and_events_unchanged` | Fresh DB control/grant/event snapshots before and after | +| Completed bootstrap is irreversible | `test_later_bootstrap_returns_audited_original_grant_conflict` | Original grant/control unchanged; exact conflict evidence | +| Bootstrap principal metadata is exact | Existing manifest test name | Literal action, permission and system principal | +| CLI outcome survives cleanup failure | Existing committed-outcome test name | Exact actor/mode forwarded; one output; cleanup attempted | +| CLI internal errors stay private | Existing TypeError test name | Infrastructure failure, no private exception text | +| Malformed CLI arguments do not execute | Existing arguments test name | Strict forbidden `_run`, bounded stdout and empty stderr | +| Interrupt is distinct | `test_bootstrap_cli_reports_interrupt` | Closed coroutine, interrupted output and cleanup attempt | +| Pre-outcome failure cannot claim success | `test_bootstrap_cli_reports_pre_outcome_cleanup_failure` | Infrastructure output on both failures | +| Admin reads conceal private fields | `test_admin_read_projects_only_public_fields` | Actual stored private sentinel values absent from response/logs; exact public fields | +| Admin read observes only caller | `test_admin_read_touches_caller_not_target` | Seeded old timestamps, independent caller/target snapshots | +| Read evidence has exact request/grant/target | `test_admin_read_records_exact_authorization_provenance` | Stored allow event matches request/correlation and matched grant | +| Missing admin target has no success effects | `test_missing_admin_target_has_concealed_response_and_no_success_effect` | Equal concealed response; timestamps and success evidence unchanged | +| Read faults cannot leak successful effects | `test_admin_read_failure_rolls_back_staged_effects` | Separate profile/link × evidence/lookup/touch/commit cases with stage-appropriate assertions | +| Grant issue/revoke faults roll back | `test_grant_mutation_commit_failure_rolls_back` | Separate operations; real staged state/event observed before fault, fresh DB restored afterward | +| Grant recovery is exact | `test_grant_mutation_exact_replay_has_one_effect` | Issue/revoke stable response, one persisted operation and linked evidence | +| Replay mismatch does not mutate | `test_grant_mutation_mismatch_preserves_product_state` | Separate issue/revoke mismatch; bounded denial evidence distinguished from forbidden success | +| Distinct duplicate differs from replay | `test_distinct_operation_duplicate_grant_is_conflict` | New key, same target/role, one grant | +| Actor eligibility denial is concealed | `test_ineligible_grant_targets_share_missing_response` | Real service/suspended/no-active-link targets and genuinely absent control | +| Project audit reads cannot cross scope | `test_project_auditor_reads_only_granted_project` | Two persisted projects, exact selected rows; foreign request denied | +| Audit authority cannot mutate | `test_audit_authority_cannot_issue_grant` | Valid active auditor; mutation denied without grant | +| Read query and grant request validation | `test_invalid_admin_request_is_bounded` | Preserve individually mapped original invalid field/cursor/selector cases | +| Concurrent bootstrap has one winner | `test_concurrent_bootstrap_has_one_persisted_winner` | Two sessions, exact control-lock wait, grant/control/success event and losing conflict | +| Same-key concurrency recovers | `test_concurrent_same_key_grant_returns_one_result` | Exact reservation wait, matching outputs, one grant and evidence pair | +| Distinct-key concurrency cannot double issue | `test_concurrent_distinct_keys_create_one_active_grant` | Exact control wait, 201/409, one persisted grant | +| Cross-revoke retains effective administrator | `test_cross_revoke_retains_one_effective_admin` | Exact control wait, one revoke and one denied caller, one effective surviving administrator | +| Issue/revoke follows serialized authority | `test_issue_against_revocation_obeys_lock_order` | Both winner orders independently; exact waiter/blocker, exact permitted/forbidden grant and events | +| Older observation cannot regress timestamps | `test_older_read_cannot_regress_committed_observation` | Ordered real requests/commits, captured newer timestamps, monotonic final stored values | +| Read holds exact authority through disclosure | `test_admin_read_blocks_exact_authority_transition` | Eight cases with exact reader blocker; later revoked caller denied without timestamp/success effects | + +Any additional original assertion not enumerated in the table must acquire its +own named survivor in the exact assertion map before the source is removed; +the table is not permission to discard field, self-protection or pagination proof. + +## Risk and review routing + +- Risk class: L1 (authorization proof; no runtime change). +- Plan and implementation: combined QA/test-delta and focused security review. +- Implementation shared-file custody: CI integrity; docs only for material + reconciliation. Reuse review only if support extraction introduces a new + abstraction rather than using existing owners. No blanket reviewer fanout. +- Human review focus: real journey retained; no mock downgrade; exact stage + and database lock proof; no arbitrary deletions or coverage-only additions. + +## Evidence + +Local: focused `test_bootstrap_cli.py` (future file), Ruff on changed Python, +`tests/test_ci_lane_catalogue.py`, existing structural-ledger/assertion-map +validation, root Commitrail/Markdown/stale scans and `git diff --check`. +Collection only may enumerate all moved cases but never claims PG execution. +Hosted: every Backend lane and aggregate, preserved coverage floors, full node +manifest with zero skips/deselections, isolated PostgreSQL/MinIO cleanup. +Record measured suite cost rather than promising an arbitrary reduction. + +Before final review, compare the fifteen unselected test bodies by AST, map +every original assertion, and probe at least one real lock-observer omission, +one rollback early-failure false proof, and one CLI privacy/dispatch defect. +Removing the intended guard must fail the named regression at its assertion, +not fail fixture setup. All full database/coverage custody stays hosted. + +## Reconciliation + +- Product PR377 shares lane catalogue and debt ledger, not this selected test + family. Preserve its registrations/debt corrections when integrating main; + do not edit its worktree, workflow, root fixture or product implementation. +- Next usable boundary: service-actor provisioning and profile/link lifecycle + matrices in the remaining authentication monolith, then remaining AUTH owners. +- Remaining risks: new isolated cases may increase fixture cost; final hosted + timings and genuine duplicate-survivor review must evaluate that tradeoff. From c96a3096e154289d0d113ffd939ce3f50d0250e1 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Mon, 7 Sep 2026 23:42:52 +0100 Subject: [PATCH 2/6] docs: close admin audit proof and fixture gaps --- .../initiatives/WS-QUAL-003/WS-QUAL-003-13.md | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md index eaef3cde7..c60b3116f 100644 --- a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md +++ b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md @@ -19,10 +19,12 @@ reviewed commits, not a separate planning PR followed by tiny cleanup PRs. Baseline is main `0e34911be4cdc25b3ec79dbcb097b62181958304` (PR379). `backend/tests/test_auth.py` retains 23 named tests. Eight selected tests occupy the bootstrap/admin-access family; fifteen other test bodies remain unchanged. -The 1,040-line `test_signed_tokens_bootstrap_and_admin_grant_lifecycle` mixes +The 1,041-line `test_signed_tokens_bootstrap_and_admin_grant_lifecycle` mixes signed-token admission, bootstrap, reads, concealment, fault injection, grant issue/revoke, scope and replay. Its final event totals depend on the entire history instead of identifying each mutation's effects. +The selected eight functions contain 203 assertion statements; this is an +inventory, not a required retained-test count or a semantic equivalence claim. `test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe` combines bootstrap, timestamp ordering, same-key recovery, distinct-key duplication, @@ -62,6 +64,10 @@ These are observed proof weaknesses, not established production defects. - `backend/scripts/test_lane_catalogue.py` and `backend/tests/test_ci_lane_catalogue.py`: register moved tests in existing lanes and prove no omission. Preserve unrelated product registrations. +- `backend/scripts/test_structure_boundary.py` and + `backend/tests/architecture/test_test_structure_boundary.py`: explicitly scan + the complete new `authorization/admin_access` directory and prove that files + lacking AUTH imports or AUTH basenames cannot evade structural inventory. ### Not allowed @@ -86,8 +92,14 @@ setup for the other tests instead of replaying every previous behavior. Setup must use real owners or valid fresh rows and must fail promptly on invalid preconditions. Faults are test-local and installed only after setup. +The new package's `conftest.py` explicitly re-exports `clear_settings_cache` +(preserving autouse), `rsa_signing_material` (preserving module scope), and +`auth_database_env` (remaining opt-in) from `tests.authentication.fixtures`. +Sibling packages do not inherit `authentication/conftest.py`. Re-export the +moved database fixture in the old monolith for its unchanged consumers. + Keep each new file below 500 lines, tests at most 120 and helpers at most 100. -Do not hide the old 1,040-line scenario in a helper. Separate meaningful failure +Do not hide the old 1,041-line scenario in a helper. Separate meaningful failure cases; do not multiply equivalent parameter combinations for coverage. Reuse `auth_concurrency_support.wait_for_named_database_lock` with exact waiter @@ -126,7 +138,7 @@ Destination paths below are relative to `tests/authorization/admin_access/`. | `test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe` | Split `test_grant_concurrency_postgresql.py` and `test_timestamp_concurrency_postgresql.py`; preserve each distinct operation/order and replace arrival-only claims with exact custody | | `test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure` | `test_read_concurrency_postgresql.py`; retain profile/link × suspend/deactivate/link-revoke/grant-revoke cases with exact blocker, independent fresh setup and denied subsequent disclosure | -## Acceptance criteria and named future proof +## Acceptance criteria Every row is a future proof requirement, not an executed result. All database, API and concurrency tests below run in hosted CI only; command tests are local. @@ -152,10 +164,25 @@ Parameter cases must remain independently identifiable in final assertion map. | Grant issue/revoke faults roll back | `test_grant_mutation_commit_failure_rolls_back` | Separate operations; real staged state/event observed before fault, fresh DB restored afterward | | Grant recovery is exact | `test_grant_mutation_exact_replay_has_one_effect` | Issue/revoke stable response, one persisted operation and linked evidence | | Replay mismatch does not mutate | `test_grant_mutation_mismatch_preserves_product_state` | Separate issue/revoke mismatch; bounded denial evidence distinguished from forbidden success | +| Issue/revoke namespaces do not alias | `test_same_caller_key_is_isolated_by_grant_operation` | Real PG: same actor and key issue then revoke; two exact operation-specific reservation rows/results and linked events, no cross-operation replay or mismatch | | Distinct duplicate differs from replay | `test_distinct_operation_duplicate_grant_is_conflict` | New key, same target/role, one grant | -| Actor eligibility denial is concealed | `test_ineligible_grant_targets_share_missing_response` | Real service/suspended/no-active-link targets and genuinely absent control | +| Actor eligibility denial is concealed | `test_ineligible_grant_targets_share_missing_response` | Real service/suspended/no-active-link targets and genuinely absent actor target; valid AuthorityControl remains present in every case | | Project audit reads cannot cross scope | `test_project_auditor_reads_only_granted_project` | Two persisted projects, exact selected rows; foreign request denied | | Audit authority cannot mutate | `test_audit_authority_cannot_issue_grant` | Valid active auditor; mutation denied without grant | +| Catalogue reads succeed under administrator authority | `test_admin_catalogue_read_returns_public_definitions` | Separate permission/role routes; preserve original exact response totals/role ordering, prove caller observation | +| Catalogue commit failure rolls back observation | `test_catalogue_read_commit_failure_rolls_back_observation` | Staged caller timestamp observed before injected commit failure; fresh DB unchanged and bounded 503 | +| Own admin profile read returns committed observation | `test_self_admin_profile_read_returns_committed_observation` | Real API+PG: persisted updated/seen/verified values advance; response matches persisted profile timestamps; one allow event and no new grant/reservation | +| Own admin link read returns committed observation | `test_self_admin_link_read_returns_committed_observation` | Real API+PG: persisted timestamps advance; response verification timestamp matches; one allow event and no new grant/reservation | +| Own PATCH commit failure rolls back | `test_admin_self_patch_commit_failure_rolls_back` | Actual new display name and observation staged before fault; fresh DB original values, no successful effect | +| Own PATCH commits requested values | `test_admin_self_patch_commits_requested_observation` | Real signed API+PG: exact display name and advanced observations persist | +| Self-grant cannot escalate authority | `test_self_admin_grant_is_denied_without_grant` | Real route, 403/self_grant_forbidden and unchanged product grants | +| Self-revoke is forbidden | `test_self_admin_revoke_preserves_grant` | Real route, 403/self_role_revoke_forbidden; exact bootstrap grant remains active | +| Revoked/absent grants are concealed equally | `test_revoked_and_absent_grants_share_concealed_revoke_response` | Real revoked row and absent UUID, normalized equal 404; no second revoke effect | +| System audit authority has bounded reads | `test_system_auditor_has_exact_read_surface` | Six independent routes: permissions, definitions, list, actor history, profile, link; real grant and persisted expected scope/rows | +| Grant list returns exact scoped rows | `test_admin_grant_list_returns_exact_scope_and_count` | Actual grants in system and project scopes; exact selected row identities and totals | +| History preserves reason but conceals identity secrets | `test_admin_grant_history_has_bounded_payload` | Exact target row/reason; signed token and subject absent from serialized response | +| Grant cursor page starts correctly | `test_admin_grant_first_page_has_bounded_cursor` | Real list with limit1; one expected row and usable next cursor; malformed derivative separately rejected | +| Target sees granted role but cannot read protected definitions | `test_target_role_projection_does_not_grant_catalogue_access` | Real grants reflected in self-read; definitions403/permission_not_granted | | Read query and grant request validation | `test_invalid_admin_request_is_bounded` | Preserve individually mapped original invalid field/cursor/selector cases | | Concurrent bootstrap has one winner | `test_concurrent_bootstrap_has_one_persisted_winner` | Two sessions, exact control-lock wait, grant/control/success event and losing conflict | | Same-key concurrency recovers | `test_concurrent_same_key_grant_returns_one_result` | Exact reservation wait, matching outputs, one grant and evidence pair | @@ -164,6 +191,8 @@ Parameter cases must remain independently identifiable in final assertion map. | Issue/revoke follows serialized authority | `test_issue_against_revocation_obeys_lock_order` | Both winner orders independently; exact waiter/blocker, exact permitted/forbidden grant and events | | Older observation cannot regress timestamps | `test_older_read_cannot_regress_committed_observation` | Ordered real requests/commits, captured newer timestamps, monotonic final stored values | | Read holds exact authority through disclosure | `test_admin_read_blocks_exact_authority_transition` | Eight cases with exact reader blocker; later revoked caller denied without timestamp/success effects | +| New owner files cannot evade structural scan | `test_admin_access_directory_is_unconditionally_scoped` | Existing architecture test module; synthetic no-AUTH-import/no-AUTH-basename fixture included recursively; omission mutation fails | +| Extracted fixtures retain isolation | `test_admin_access_fixture_collection_is_complete` (verification inventory, not an extra product test) | Mixed collection with test_auth, new CLI/PG nodes and database-reset tests resolves fixtures without shadowing root conftest; actual hosted execution proves cleanup | Any additional original assertion not enumerated in the table must acquire its own named survivor in the exact assertion map before the source is removed; @@ -204,3 +233,13 @@ not fail fixture setup. All full database/coverage custody stays hosted. matrices in the remaining authentication monolith, then remaining AUTH owners. - Remaining risks: new isolated cases may increase fixture cost; final hosted timings and genuine duplicate-survivor review must evaluate that tradeoff. + +## Plan review corrections + +Pre-implementation review found missing explicit structural-directory custody, +sibling fixture exports, and named preservation rows for several original +behaviors. These are now required above. The absent-target fixture keeps the +real control row; a missing control row is an infrastructure error, not an +actor-concealment negative. Same-key issue/revoke operation isolation is distinct +from same-operation recovery and control-row serialization. These corrections +establish plan feasibility only; they do not claim future tests have run. From 8c1625b7af95e7833ac40980599bc450e9d57596 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Mon, 7 Sep 2026 23:54:27 +0100 Subject: [PATCH 3/6] test(auth): isolate bootstrap CLI privacy and outcome proof --- .ci/auth-boundaries/TEST_STRUCTURE_DEBT.json | 42 +- .../assertion-maps/WS-QUAL-003-13.json | 567 ++++++++++++++++++ .../initiatives/WS-QUAL-003/WS-QUAL-003-13.md | 18 + backend/scripts/test_lane_catalogue.py | 1 + backend/scripts/test_structure_boundary.py | 7 +- .../test_test_structure_boundary.py | 8 + backend/tests/authentication/fixtures.py | 18 + .../authorization/admin_access/__init__.py | 1 + .../authorization/admin_access/conftest.py | 7 + .../admin_access/test_bootstrap_cli.py | 141 +++++ backend/tests/test_auth.py | 123 +--- backend/tests/test_ci_lane_catalogue.py | 1 + 12 files changed, 790 insertions(+), 144 deletions(-) create mode 100644 .ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json create mode 100644 backend/tests/authorization/admin_access/__init__.py create mode 100644 backend/tests/authorization/admin_access/conftest.py create mode 100644 backend/tests/authorization/admin_access/test_bootstrap_cli.py diff --git a/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json b/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json index e4bee12bc..ac368e32c 100644 --- a/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json +++ b/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json @@ -194,11 +194,11 @@ }, { "capability": "unassigned_legacy_auth", - "content_sha256": "cfaf237be44f3060b9c9a0d026dde3c0cdba96d67034f14c838101a51dc38d47", - "end_line": 5822, + "content_sha256": "44c4d5dd56bdd2a43bde1d88b11caf5e60c59254d3a9769de6792a668db3b77a", + "end_line": 5701, "hard_limit": 1200, "kind": "test_file", - "observed_lines": 5822, + "observed_lines": 5701, "path": "backend/tests/test_auth.py", "qualified_symbol": null, "removal_chunk": "WS-AUTH-003-CLOSE", @@ -399,110 +399,110 @@ { "capability": "unassigned_legacy_auth", "content_sha256": "44b9858d132d384cd10c6b8b8fae096ade7c3fced6780cc2c142e59b4162d97d", - "end_line": 2253, + "end_line": 2132, "hard_limit": 120, "kind": "test_function", "observed_lines": 280, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 1974 + "start_line": 1853 }, { "capability": "unassigned_legacy_auth", "content_sha256": "9df08af6d7d3193c9112ac885fbe242b0f6ef072dfe9536f91980a61d14a7b4c", - "end_line": 5802, + "end_line": 5681, "hard_limit": 120, "kind": "test_function", "observed_lines": 879, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_identity_link_lifecycle_real_postgres_concurrency", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 4924 + "start_line": 4803 }, { "capability": "unassigned_legacy_auth", "content_sha256": "15c7147c11fa1802f43480b38a3678ac1a2586320ae2f0013622f1d63b2a3806", - "end_line": 4479, + "end_line": 4358, "hard_limit": 120, "kind": "test_function", "observed_lines": 535, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_identity_link_lifecycle_real_postgres_matrix", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 3945 + "start_line": 3824 }, { "capability": "unassigned_legacy_auth", "content_sha256": "188db6b76b3f6dbe4077dbbb724bc9fe7529058b099cc7409bc5a443686a096a", - "end_line": 4921, + "end_line": 4800, "hard_limit": 120, "kind": "test_function", "observed_lines": 440, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_profile_lifecycle_real_postgres_concurrency", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 4482 + "start_line": 4361 }, { "capability": "unassigned_legacy_auth", "content_sha256": "eca9eeff229ee37c103188f9a31e278773a69e96f2fd354662723f840cf8f16a", - "end_line": 3942, + "end_line": 3821, "hard_limit": 120, "kind": "test_function", "observed_lines": 482, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_profile_lifecycle_real_postgres_matrix", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 3461 + "start_line": 3340 }, { "capability": "unassigned_legacy_auth", "content_sha256": "e1fd679295947e120c6da520bd138a78a8e133e44f8dde91010de29354e88f5b", - "end_line": 1971, + "end_line": 1850, "hard_limit": 120, "kind": "test_function", "observed_lines": 485, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 1487 + "start_line": 1366 }, { "capability": "unassigned_legacy_auth", "content_sha256": "8ea087b906726103295a019967f8c38e42b55deb4e912fda3a41289fda23f35d", - "end_line": 2978, + "end_line": 2857, "hard_limit": 120, "kind": "test_function", "observed_lines": 647, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_controlled_service_actor_provisioning_includes_project_setup_and_is_atomic", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 2332 + "start_line": 2211 }, { "capability": "unassigned_legacy_auth", "content_sha256": "d26732dd125f8c2062b5a4b45b59fbccd283ee04939a9da7be1576235524292f", - "end_line": 3389, + "end_line": 3268, "hard_limit": 120, "kind": "test_function", "observed_lines": 409, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_service_actor_provisioning_failure_and_authority_races_are_atomic", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 2981 + "start_line": 2860 }, { "capability": "unassigned_legacy_auth", "content_sha256": "a7e36b433ed775ab82e7ff92c013aab3a1cee14fbbed6f4ddace351ab936e24c", - "end_line": 1371, + "end_line": 1353, "hard_limit": 120, "kind": "test_function", "observed_lines": 1041, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_signed_tokens_bootstrap_and_admin_grant_lifecycle", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 331 + "start_line": 313 }, { "capability": "unassigned_legacy_auth", diff --git a/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json b/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json new file mode 100644 index 000000000..9d55f90db --- /dev/null +++ b/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json @@ -0,0 +1,567 @@ +{ + "chunk_id": "WS-QUAL-003-13", + "schema": "workstream.auth-assertion-map.v1", + "mappings": [ + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue", + "old_assertion_id": "assertion:1375:1375:e25f783cf32782e502386a114384abd167f7dc7e5c44aaa30cda41bc7d313e9f", + "old_source_span": [ + 1375, + 1375 + ], + "old_content_sha256": "e25f783cf32782e502386a114384abd167f7dc7e5c44aaa30cda41bc7d313e9f", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue", + "invariant_category": "bootstrap_command_manifest_matches_the_active_catalogue", + "target_layer": "domain", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + } + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue", + "old_assertion_id": "assertion:1376:1376:8580c25b9d0e709842cf64b324bf13f09a0e8ab3c0655e17420fc005f94e2f82", + "old_source_span": [ + 1376, + 1376 + ], + "old_content_sha256": "8580c25b9d0e709842cf64b324bf13f09a0e8ab3c0655e17420fc005f94e2f82", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue", + "invariant_category": "bootstrap_command_manifest_matches_the_active_catalogue", + "target_layer": "domain", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + } + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue", + "old_assertion_id": "assertion:1377:1377:b2d1927409a59c144ee7a226736a7d1b35a993ce2a00e4879917d0d746d30812", + "old_source_span": [ + 1377, + 1377 + ], + "old_content_sha256": "b2d1927409a59c144ee7a226736a7d1b35a993ce2a00e4879917d0d746d30812", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue", + "invariant_category": "bootstrap_command_manifest_matches_the_active_catalogue", + "target_layer": "domain", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + } + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "old_assertion_id": "assertion:1387:1387:a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", + "old_source_span": [ + 1387, + 1387 + ], + "old_content_sha256": "a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "invariant_category": "bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "old_assertion_id": "assertion:1401:1401:ff5ee387d6f17cf2a9e6e9fb696a637d7d34613ea4b94bd8c2b3eb44918187e0", + "old_source_span": [ + 1401, + 1401 + ], + "old_content_sha256": "ff5ee387d6f17cf2a9e6e9fb696a637d7d34613ea4b94bd8c2b3eb44918187e0", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "invariant_category": "bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "old_assertion_id": "assertion:1402:1407:6d4dcbfb8012669b138a3fd67c3b41460ced17e0008408c0b9d7c9f591cf2917", + "old_source_span": [ + 1402, + 1407 + ], + "old_content_sha256": "6d4dcbfb8012669b138a3fd67c3b41460ced17e0008408c0b9d7c9f591cf2917", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "invariant_category": "bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "old_assertion_id": "assertion:1415:1415:a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", + "old_source_span": [ + 1415, + 1415 + ], + "old_content_sha256": "a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "invariant_category": "bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "old_assertion_id": "assertion:1424:1424:c7598e5f87e2e832d39a203f626df63780e38526e411ceb322b4bbf7c063ff29", + "old_source_span": [ + 1424, + 1424 + ], + "old_content_sha256": "c7598e5f87e2e832d39a203f626df63780e38526e411ceb322b4bbf7c063ff29", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "invariant_category": "bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "old_assertion_id": "assertion:1425:1425:7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", + "old_source_span": [ + 1425, + 1425 + ], + "old_content_sha256": "7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "invariant_category": "bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", + "old_assertion_id": "assertion:1451:1451:a580a3e1405721e0a5eb3419522b1106915083e2aba73324140ffa0c39c0a637", + "old_source_span": [ + 1451, + 1451 + ], + "old_content_sha256": "a580a3e1405721e0a5eb3419522b1106915083e2aba73324140ffa0c39c0a637", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", + "invariant_category": "bootstrap_cli_rejects_arguments_without_echoing_them", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", + "old_assertion_id": "assertion:1452:1452:6dc7ff258b8274cbe231e06ab9d99722aa2e4eefc4bb3aec905ea73ec530f474", + "old_source_span": [ + 1452, + 1452 + ], + "old_content_sha256": "6dc7ff258b8274cbe231e06ab9d99722aa2e4eefc4bb3aec905ea73ec530f474", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", + "invariant_category": "bootstrap_cli_rejects_arguments_without_echoing_them", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", + "old_assertion_id": "assertion:1471:1471:a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", + "old_source_span": [ + 1471, + 1471 + ], + "old_content_sha256": "a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_interrupt", + "invariant_category": "bootstrap_cli_reports_interrupt", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", + "old_assertion_id": "assertion:1472:1472:145c4ca500b42a85a114e20e5dc2162706c8b809245b5875a9f0e83b187f6f06", + "old_source_span": [ + 1472, + 1472 + ], + "old_content_sha256": "145c4ca500b42a85a114e20e5dc2162706c8b809245b5875a9f0e83b187f6f06", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_interrupt", + "invariant_category": "bootstrap_cli_reports_interrupt", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", + "old_assertion_id": "assertion:1483:1483:a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", + "old_source_span": [ + 1483, + 1483 + ], + "old_content_sha256": "a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_pre_outcome_cleanup_failure", + "invariant_category": "bootstrap_cli_reports_pre_outcome_cleanup_failure", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + }, + { + "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", + "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", + "old_assertion_id": "assertion:1484:1484:7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", + "old_source_span": [ + 1484, + 1484 + ], + "old_content_sha256": "7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", + "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_pre_outcome_cleanup_failure", + "invariant_category": "bootstrap_cli_reports_pre_outcome_cleanup_failure", + "target_layer": "service", + "security_dimensions": { + "concurrency": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "lock_order": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "denial_side_effects": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "replay": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "revocation": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "evidence": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "transaction_ownership": { + "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." + }, + "concealment": "preserved" + } + } + ] +} diff --git a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md index c60b3116f..1084a48cf 100644 --- a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md +++ b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md @@ -243,3 +243,21 @@ real control row; a missing control row is an infrastructure error, not an actor-concealment negative. Same-key issue/revoke operation isolation is distinct from same-operation recovery and control-row serialization. These corrections establish plan feasibility only; they do not claim future tests have run. + +## Implementation checkpoints + +The first checkpoint moves five original CLI functions into six focused +functions (seven expanded cases become eight because interrupt and pre-outcome +failure are independent). All fifteen original assertion spans are mapped. +Exact actor/mode forwarding, forbidden dispatch on malformed arguments, cleanup +calls, and empty stderr strengthen the original command proof. A process-local +stderr-leak mutant survives the original malformed-argument test but fails the +new stderr assertion. This is a test defect, not an observed production leak. + +The database fixture moves unchanged to shared authentication fixtures, with +explicit sibling exports. The new owner directory is explicitly scanned and +registered in existing lanes. All eighteen tests still in the monolith retain +AST-identical bodies at this checkpoint. Mixed fixture collection succeeds; +that is not PostgreSQL execution. The three selected large API/concurrency +functions and their 188 original assertion spans still require the subsequent +implementation checkpoint and hosted proof in this same PR. diff --git a/backend/scripts/test_lane_catalogue.py b/backend/scripts/test_lane_catalogue.py index b7dec0d77..ef2094dab 100644 --- a/backend/scripts/test_lane_catalogue.py +++ b/backend/scripts/test_lane_catalogue.py @@ -122,6 +122,7 @@ class TestLane: "tests/test_api_rate_controls.py", "tests/test_audit.py", "tests/test_auth.py", + "tests/authorization/admin_access/test_bootstrap_cli.py", "tests/test_auth_concurrency_observer.py", "tests/test_authorization.py", "tests/authorization/guide_compilation/test_adapter_contract.py", diff --git a/backend/scripts/test_structure_boundary.py b/backend/scripts/test_structure_boundary.py index 8340fb37e..e82c99e23 100644 --- a/backend/scripts/test_structure_boundary.py +++ b/backend/scripts/test_structure_boundary.py @@ -147,7 +147,12 @@ def scoped_test_paths(root: Path) -> list[Path]: path = root / value if value.startswith("backend/tests/") and path.is_file(): result.add(path) - for directory in (POL_03A_TEST_ROOT, "backend/tests/actors", "backend/tests/authentication"): + for directory in ( + POL_03A_TEST_ROOT, + "backend/tests/actors", + "backend/tests/authentication", + "backend/tests/authorization/admin_access", + ): selected = root / directory if selected.is_dir(): result.update(selected.rglob("*.py")) diff --git a/backend/tests/architecture/test_test_structure_boundary.py b/backend/tests/architecture/test_test_structure_boundary.py index bf411e9d4..88f7fa5c9 100644 --- a/backend/tests/architecture/test_test_structure_boundary.py +++ b/backend/tests/architecture/test_test_structure_boundary.py @@ -80,6 +80,14 @@ def test_inventory_records_one_oversized_production_function(tmp_path: Path) -> assert functions[0].observed_lines == 102 +def test_admin_access_directory_is_unconditionally_scoped(tmp_path: Path) -> None: + """Nested owner files need no AUTH basename or direct import to be checked.""" + path = tmp_path / "backend/tests/authorization/admin_access/nested/test_cli.py" + _write(path, "import pytest\npytestmark = pytest.mark.skip\n") + assert path in structure.scoped_test_paths(tmp_path) + assert structure.weak_python(path) + + def test_inventory_records_one_mixed_test_beyond_the_hard_limit(tmp_path: Path) -> None: """An AUTH test beyond 120 lines is recorded independently of file size.""" body = "\n".join(f" assert {index} == {index}" for index in range(120)) diff --git a/backend/tests/authentication/fixtures.py b/backend/tests/authentication/fixtures.py index ad86d581f..924c1ba34 100644 --- a/backend/tests/authentication/fixtures.py +++ b/backend/tests/authentication/fixtures.py @@ -26,3 +26,21 @@ def clear_settings_cache() -> Iterator[None]: def rsa_signing_material() -> tuple[rsa.RSAPrivateKey, dict[str, Any]]: private_key = rsa.generate_private_key(public_exponent=65_537, key_size=2_048) return private_key, rsa_public_jwk(private_key, kid="issuer-key-1") + + +@pytest.fixture +def auth_database_env( + monkeypatch: pytest.MonkeyPatch, + clean_postgres_database: str, +) -> Iterator[str]: + """Run auth route persistence tests against a clean migrated schema.""" + monkeypatch.setenv("WORKSTREAM_DATABASE_URL", clean_postgres_database) + monkeypatch.setenv( + "WORKSTREAM_API_RATE_LIMIT_KEY_SECRET", + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=", + ) + get_settings.cache_clear() + try: + yield clean_postgres_database + finally: + get_settings.cache_clear() diff --git a/backend/tests/authorization/admin_access/__init__.py b/backend/tests/authorization/admin_access/__init__.py new file mode 100644 index 000000000..02ee426c1 --- /dev/null +++ b/backend/tests/authorization/admin_access/__init__.py @@ -0,0 +1 @@ +"""Bootstrap and administrative-access behavior proofs.""" diff --git a/backend/tests/authorization/admin_access/conftest.py b/backend/tests/authorization/admin_access/conftest.py new file mode 100644 index 000000000..be8f38d81 --- /dev/null +++ b/backend/tests/authorization/admin_access/conftest.py @@ -0,0 +1,7 @@ +"""Explicit sibling-package fixture custody; PostgreSQL remains opt-in.""" + +from tests.authentication.fixtures import ( + auth_database_env as auth_database_env, + clear_settings_cache as clear_settings_cache, + rsa_signing_material as rsa_signing_material, +) diff --git a/backend/tests/authorization/admin_access/test_bootstrap_cli.py b/backend/tests/authorization/admin_access/test_bootstrap_cli.py new file mode 100644 index 000000000..37fd9455a --- /dev/null +++ b/backend/tests/authorization/admin_access/test_bootstrap_cli.py @@ -0,0 +1,141 @@ +"""Local command privacy and outcome handling, not database bootstrap proof.""" + +import json +from uuid import UUID, uuid4 + +import pytest + +from scripts import bootstrap_access_administrator as command + + +def test_bootstrap_command_manifest_matches_the_active_catalogue() -> None: + manifest = command.BOOTSTRAP_COMMAND_MANIFEST + assert manifest.action_id.value == "admin_role_grant.bootstrap" + assert manifest.permission_id.value == "admin_role.grant" + assert manifest.principal == "workstream:system:bootstrap" + + +def test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails( + monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +) -> None: + actor_id, grant_id = uuid4(), uuid4() + outcome = { + "result_code": "bootstrapped", + "actor_profile_id": str(actor_id), + "grant_id": str(grant_id), + "changed": True, + } + calls = [] + + async def successful_run(selected_actor: UUID, *, execute: bool): + assert selected_actor == actor_id + assert execute is True + calls.append("run") + return 0, outcome + + async def failed_cleanup() -> None: + calls.append("cleanup") + raise RuntimeError("private cleanup failure") + + monkeypatch.setattr(command, "_run", successful_run) + monkeypatch.setattr(command, "dispose_engine", failed_cleanup) + assert command.main(["--actor-profile-id", str(actor_id), "--execute"]) == 0 + captured = capsys.readouterr() + assert json.loads(captured.out) == outcome + assert captured.err == "" + assert calls == ["run", "cleanup"] + + +def test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request( + monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +) -> None: + actor_id = uuid4() + calls = [] + + async def broken_run(selected_actor: UUID, *, execute: bool): + assert selected_actor == actor_id + assert execute is True + calls.append("run") + raise TypeError("private internal contract failure") + + async def clean_disposal() -> None: + calls.append("cleanup") + + monkeypatch.setattr(command, "_run", broken_run) + monkeypatch.setattr(command, "dispose_engine", clean_disposal) + assert command.main(["--actor-profile-id", str(actor_id), "--execute"]) == 1 + captured = capsys.readouterr() + assert json.loads(captured.out) == {"result_code": "infrastructure_failure"} + assert captured.err == "" + assert calls == ["run", "cleanup"] + + +@pytest.mark.parametrize( + "argv", + [ + pytest.param([], id="missing-required-arguments"), + pytest.param( + ["--actor-profile-id", "private-not-a-uuid", "--execute"], id="invalid-uuid" + ), + pytest.param( + ["--actor-profile-id", str(uuid4()), "--dry-run", "--execute"], + id="mutually-exclusive-modes", + ), + ], +) +def test_bootstrap_cli_rejects_arguments_without_echoing_them( + argv: list[str], monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +) -> None: + calls = [] + + async def forbidden_run(*args, **kwargs): + calls.append("forbidden_run") + raise AssertionError("malformed arguments entered execution") + + async def clean_disposal() -> None: + calls.append("cleanup") + + monkeypatch.setattr(command, "_run", forbidden_run) + monkeypatch.setattr(command, "dispose_engine", clean_disposal) + assert command.main(argv) == 2 + captured = capsys.readouterr() + assert json.loads(captured.out) == {"result_code": "invalid_request"} + assert captured.err == "" + assert calls == ["cleanup"] + + +def test_bootstrap_cli_reports_interrupt( + monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +) -> None: + calls = [] + + def interrupted_then_clean(coroutine): + calls.append(coroutine.cr_code.co_name) + coroutine.close() + if len(calls) == 1: + raise KeyboardInterrupt + + monkeypatch.setattr(command.asyncio, "run", interrupted_then_clean) + assert command.main(["--actor-profile-id", str(uuid4()), "--execute"]) == 1 + captured = capsys.readouterr() + assert json.loads(captured.out) == {"result_code": "interrupted"} + assert captured.err == "" + assert calls == ["_run", "dispose_engine"] + + +def test_bootstrap_cli_reports_pre_outcome_cleanup_failure( + monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +) -> None: + calls = [] + + def failed_before_and_during_cleanup(coroutine): + calls.append(coroutine.cr_code.co_name) + coroutine.close() + raise RuntimeError("private infrastructure failure") + + monkeypatch.setattr(command.asyncio, "run", failed_before_and_during_cleanup) + assert command.main(["--actor-profile-id", str(uuid4()), "--execute"]) == 1 + captured = capsys.readouterr() + assert json.loads(captured.out) == {"result_code": "infrastructure_failure"} + assert captured.err == "" + assert calls == ["_run", "dispose_engine"] diff --git a/backend/tests/test_auth.py b/backend/tests/test_auth.py index 675e4909b..0a630b969 100644 --- a/backend/tests/test_auth.py +++ b/backend/tests/test_auth.py @@ -6,6 +6,7 @@ jwks_transport, ) from tests.authentication.fixtures import ( + auth_database_env as auth_database_env, clear_settings_cache as clear_settings_cache, rsa_signing_material as rsa_signing_material, ) @@ -15,7 +16,6 @@ import asyncio import json import logging -from collections.abc import Iterator from datetime import UTC, datetime from functools import partial from pathlib import Path @@ -69,10 +69,8 @@ from auth_concurrency_support import ordered_control_requests, wait_for_named_database_lock from app.modules.tasks.models import AuditEvent from scripts.bootstrap_access_administrator import ( - BOOTSTRAP_COMMAND_MANIFEST, _run as run_admin_bootstrap, ) -from scripts import bootstrap_access_administrator as bootstrap_command def _application_paths(app) -> set[str]: @@ -166,22 +164,6 @@ def current_task_name() -> str: return task.get_name() -@pytest.fixture -def auth_database_env( - monkeypatch: pytest.MonkeyPatch, - clean_postgres_database: str, -) -> Iterator[str]: - """Run auth route persistence tests against a clean migrated schema.""" - monkeypatch.setenv("WORKSTREAM_DATABASE_URL", clean_postgres_database) - monkeypatch.setenv( - "WORKSTREAM_API_RATE_LIMIT_KEY_SECRET", - "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=", - ) - get_settings.cache_clear() - try: - yield clean_postgres_database - finally: - get_settings.cache_clear() def test_legacy_compatibility_dependency_has_fixed_consumer_allowlist() -> None: @@ -1371,117 +1353,14 @@ async def assert_failed_admin_read(path: str) -> None: await db_session.dispose_engine() -def test_bootstrap_command_manifest_matches_the_active_catalogue() -> None: - assert BOOTSTRAP_COMMAND_MANIFEST.action_id.value == "admin_role_grant.bootstrap" - assert BOOTSTRAP_COMMAND_MANIFEST.permission_id.value == "admin_role.grant" - assert BOOTSTRAP_COMMAND_MANIFEST.principal == "workstream:system:bootstrap" - - -def test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails( - monkeypatch: pytest.MonkeyPatch, - capsys: pytest.CaptureFixture[str], -) -> None: - actor_id, grant_id = uuid4(), uuid4() - - async def successful_run(_actor_profile_id: UUID, *, execute: bool): - assert execute is True - return 0, { - "result_code": "bootstrapped", - "actor_profile_id": str(actor_id), - "grant_id": str(grant_id), - "changed": True, - } - - async def failed_cleanup() -> None: - raise RuntimeError("forced cleanup failure") - - monkeypatch.setattr(bootstrap_command, "_run", successful_run) - monkeypatch.setattr(bootstrap_command, "dispose_engine", failed_cleanup) - assert bootstrap_command.main(["--actor-profile-id", str(actor_id), "--execute"]) == 0 - assert json.loads(capsys.readouterr().out) == { - "result_code": "bootstrapped", - "actor_profile_id": str(actor_id), - "grant_id": str(grant_id), - "changed": True, - } -def test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request( - monkeypatch: pytest.MonkeyPatch, - capsys: pytest.CaptureFixture[str], -) -> None: - async def broken_run(_actor_profile_id: UUID, *, execute: bool): - assert execute is True - raise TypeError("forced internal contract failure") - async def clean_disposal() -> None: - return None - monkeypatch.setattr(bootstrap_command, "_run", broken_run) - monkeypatch.setattr(bootstrap_command, "dispose_engine", clean_disposal) - assert bootstrap_command.main(["--actor-profile-id", str(uuid4()), "--execute"]) == 1 - assert json.loads(capsys.readouterr().out) == {"result_code": "infrastructure_failure"} -@pytest.mark.parametrize( - ("argv", "expected_code", "expected_result"), - [ - ([], 2, "invalid_request"), - (["--actor-profile-id", "not-a-uuid", "--execute"], 2, "invalid_request"), - ( - ["--actor-profile-id", str(uuid4()), "--dry-run", "--execute"], - 2, - "invalid_request", - ), - ], -) -def test_bootstrap_cli_rejects_arguments_without_echoing_them( - argv: list[str], - expected_code: int, - expected_result: str, - monkeypatch: pytest.MonkeyPatch, - capsys: pytest.CaptureFixture[str], -) -> None: - async def clean_disposal() -> None: - return None - - monkeypatch.setattr(bootstrap_command, "dispose_engine", clean_disposal) - assert bootstrap_command.main(argv) == expected_code - assert json.loads(capsys.readouterr().out) == {"result_code": expected_result} - - -def test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure( - monkeypatch: pytest.MonkeyPatch, - capsys: pytest.CaptureFixture[str], -) -> None: - actor_id = uuid4() - calls = 0 - - def interrupted_then_clean(coroutine): - nonlocal calls - calls += 1 - coroutine.close() - if calls == 1: - raise KeyboardInterrupt - return None - - monkeypatch.setattr(bootstrap_command.asyncio, "run", interrupted_then_clean) - assert bootstrap_command.main(["--actor-profile-id", str(actor_id), "--execute"]) == 1 - assert json.loads(capsys.readouterr().out) == {"result_code": "interrupted"} - - calls = 0 - - def failed_before_and_during_cleanup(coroutine): - nonlocal calls - calls += 1 - coroutine.close() - raise RuntimeError(f"failure-{calls}") - - monkeypatch.setattr(bootstrap_command.asyncio, "run", failed_before_and_during_cleanup) - assert bootstrap_command.main(["--actor-profile-id", str(actor_id), "--execute"]) == 1 - assert json.loads(capsys.readouterr().out) == {"result_code": "infrastructure_failure"} async def test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe( diff --git a/backend/tests/test_ci_lane_catalogue.py b/backend/tests/test_ci_lane_catalogue.py index 9b0f2519a..d17b48b62 100644 --- a/backend/tests/test_ci_lane_catalogue.py +++ b/backend/tests/test_ci_lane_catalogue.py @@ -129,6 +129,7 @@ def test_measured_hotspots_have_explicit_semantic_owners() -> None: runner.ADMIN_RUNNER_MODULE, } == modules_by_lane["schema_contracts"] assert { + "tests/authorization/admin_access/test_bootstrap_cli.py", "tests/actors/test_first_access_postgresql.py", "tests/authorization/guide_compilation_projections/test_replay_evidence.py", "tests/test_auth_concurrency_observer.py", From 93ffce54c017584cd83cee9a64e116210c5f2e41 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Tue, 8 Sep 2026 00:40:51 +0100 Subject: [PATCH 4/6] test(auth): isolate admin API rollback and exact lock proof --- .ci/auth-boundaries/TEST_STRUCTURE_DEBT.json | 66 +- .../assertion-maps/WS-QUAL-003-13.json | 764 ++----- .../initiatives/WS-QUAL-003/WS-QUAL-003-13.md | 27 +- backend/scripts/test_lane_catalogue.py | 10 + .../admin_access/concurrency_support.py | 227 ++ .../authorization/admin_access/conftest.py | 4 + .../admin_access/fault_support.py | 87 + .../authorization/admin_access/fixtures.py | 43 + .../admin_access/read_support.py | 124 ++ .../authorization/admin_access/support.py | 204 ++ .../test_admin_reads_postgresql.py | 224 ++ .../admin_access/test_api_journey.py | 21 + .../admin_access/test_bootstrap_postgresql.py | 77 + .../test_failure_atomicity_postgresql.py | 154 ++ .../admin_access/test_grant_api_postgresql.py | 273 +++ .../test_grant_concurrency_postgresql.py | 245 +++ .../test_grant_reads_postgresql.py | 198 ++ .../test_grant_validation_postgresql.py | 86 + .../test_read_concurrency_postgresql.py | 54 + .../test_timestamp_concurrency_postgresql.py | 94 + backend/tests/test_auth.py | 1826 +---------------- backend/tests/test_ci_lane_catalogue.py | 10 + 22 files changed, 2380 insertions(+), 2438 deletions(-) create mode 100644 backend/tests/authorization/admin_access/concurrency_support.py create mode 100644 backend/tests/authorization/admin_access/fault_support.py create mode 100644 backend/tests/authorization/admin_access/fixtures.py create mode 100644 backend/tests/authorization/admin_access/read_support.py create mode 100644 backend/tests/authorization/admin_access/support.py create mode 100644 backend/tests/authorization/admin_access/test_admin_reads_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_api_journey.py create mode 100644 backend/tests/authorization/admin_access/test_bootstrap_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_grant_api_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_grant_reads_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_grant_validation_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py create mode 100644 backend/tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py diff --git a/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json b/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json index ac368e32c..cfe50501d 100644 --- a/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json +++ b/.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json @@ -194,11 +194,11 @@ }, { "capability": "unassigned_legacy_auth", - "content_sha256": "44c4d5dd56bdd2a43bde1d88b11caf5e60c59254d3a9769de6792a668db3b77a", - "end_line": 5701, + "content_sha256": "6f7d6f8a812cc289196a9468527159cf344650290f880bd5cfcb9e3a7f613ce9", + "end_line": 3877, "hard_limit": 1200, "kind": "test_file", - "observed_lines": 5701, + "observed_lines": 3877, "path": "backend/tests/test_auth.py", "qualified_symbol": null, "removal_chunk": "WS-AUTH-003-CLOSE", @@ -396,113 +396,77 @@ "removal_chunk": "WS-AUTH-003-CLOSE", "start_line": 1104 }, - { - "capability": "unassigned_legacy_auth", - "content_sha256": "44b9858d132d384cd10c6b8b8fae096ade7c3fced6780cc2c142e59b4162d97d", - "end_line": 2132, - "hard_limit": 120, - "kind": "test_function", - "observed_lines": 280, - "path": "backend/tests/test_auth.py", - "qualified_symbol": "test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure", - "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 1853 - }, { "capability": "unassigned_legacy_auth", "content_sha256": "9df08af6d7d3193c9112ac885fbe242b0f6ef072dfe9536f91980a61d14a7b4c", - "end_line": 5681, + "end_line": 3857, "hard_limit": 120, "kind": "test_function", "observed_lines": 879, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_identity_link_lifecycle_real_postgres_concurrency", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 4803 + "start_line": 2979 }, { "capability": "unassigned_legacy_auth", "content_sha256": "15c7147c11fa1802f43480b38a3678ac1a2586320ae2f0013622f1d63b2a3806", - "end_line": 4358, + "end_line": 2534, "hard_limit": 120, "kind": "test_function", "observed_lines": 535, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_identity_link_lifecycle_real_postgres_matrix", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 3824 + "start_line": 2000 }, { "capability": "unassigned_legacy_auth", "content_sha256": "188db6b76b3f6dbe4077dbbb724bc9fe7529058b099cc7409bc5a443686a096a", - "end_line": 4800, + "end_line": 2976, "hard_limit": 120, "kind": "test_function", "observed_lines": 440, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_profile_lifecycle_real_postgres_concurrency", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 4361 + "start_line": 2537 }, { "capability": "unassigned_legacy_auth", "content_sha256": "eca9eeff229ee37c103188f9a31e278773a69e96f2fd354662723f840cf8f16a", - "end_line": 3821, + "end_line": 1997, "hard_limit": 120, "kind": "test_function", "observed_lines": 482, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_actor_profile_lifecycle_real_postgres_matrix", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 3340 - }, - { - "capability": "unassigned_legacy_auth", - "content_sha256": "e1fd679295947e120c6da520bd138a78a8e133e44f8dde91010de29354e88f5b", - "end_line": 1850, - "hard_limit": 120, - "kind": "test_function", - "observed_lines": 485, - "path": "backend/tests/test_auth.py", - "qualified_symbol": "test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe", - "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 1366 + "start_line": 1516 }, { "capability": "unassigned_legacy_auth", "content_sha256": "8ea087b906726103295a019967f8c38e42b55deb4e912fda3a41289fda23f35d", - "end_line": 2857, + "end_line": 1033, "hard_limit": 120, "kind": "test_function", "observed_lines": 647, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_controlled_service_actor_provisioning_includes_project_setup_and_is_atomic", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 2211 + "start_line": 387 }, { "capability": "unassigned_legacy_auth", "content_sha256": "d26732dd125f8c2062b5a4b45b59fbccd283ee04939a9da7be1576235524292f", - "end_line": 3268, + "end_line": 1444, "hard_limit": 120, "kind": "test_function", "observed_lines": 409, "path": "backend/tests/test_auth.py", "qualified_symbol": "test_service_actor_provisioning_failure_and_authority_races_are_atomic", "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 2860 - }, - { - "capability": "unassigned_legacy_auth", - "content_sha256": "a7e36b433ed775ab82e7ff92c013aab3a1cee14fbbed6f4ddace351ab936e24c", - "end_line": 1353, - "hard_limit": 120, - "kind": "test_function", - "observed_lines": 1041, - "path": "backend/tests/test_auth.py", - "qualified_symbol": "test_signed_tokens_bootstrap_and_admin_grant_lifecycle", - "removal_chunk": "WS-AUTH-003-CLOSE", - "start_line": 313 + "start_line": 1036 }, { "capability": "unassigned_legacy_auth", diff --git a/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json b/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json index 9d55f90db..c32de562f 100644 --- a/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json +++ b/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json @@ -2,566 +2,208 @@ "chunk_id": "WS-QUAL-003-13", "schema": "workstream.auth-assertion-map.v1", "mappings": [ - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue", - "old_assertion_id": "assertion:1375:1375:e25f783cf32782e502386a114384abd167f7dc7e5c44aaa30cda41bc7d313e9f", - "old_source_span": [ - 1375, - 1375 - ], - "old_content_sha256": "e25f783cf32782e502386a114384abd167f7dc7e5c44aaa30cda41bc7d313e9f", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue", - "invariant_category": "bootstrap_command_manifest_matches_the_active_catalogue", - "target_layer": "domain", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - } - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue", - "old_assertion_id": "assertion:1376:1376:8580c25b9d0e709842cf64b324bf13f09a0e8ab3c0655e17420fc005f94e2f82", - "old_source_span": [ - 1376, - 1376 - ], - "old_content_sha256": "8580c25b9d0e709842cf64b324bf13f09a0e8ab3c0655e17420fc005f94e2f82", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue", - "invariant_category": "bootstrap_command_manifest_matches_the_active_catalogue", - "target_layer": "domain", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - } - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue", - "old_assertion_id": "assertion:1377:1377:b2d1927409a59c144ee7a226736a7d1b35a993ce2a00e4879917d0d746d30812", - "old_source_span": [ - 1377, - 1377 - ], - "old_content_sha256": "b2d1927409a59c144ee7a226736a7d1b35a993ce2a00e4879917d0d746d30812", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue", - "invariant_category": "bootstrap_command_manifest_matches_the_active_catalogue", - "target_layer": "domain", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - } - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "old_assertion_id": "assertion:1387:1387:a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", - "old_source_span": [ - 1387, - 1387 - ], - "old_content_sha256": "a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "invariant_category": "bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "old_assertion_id": "assertion:1401:1401:ff5ee387d6f17cf2a9e6e9fb696a637d7d34613ea4b94bd8c2b3eb44918187e0", - "old_source_span": [ - 1401, - 1401 - ], - "old_content_sha256": "ff5ee387d6f17cf2a9e6e9fb696a637d7d34613ea4b94bd8c2b3eb44918187e0", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "invariant_category": "bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "old_assertion_id": "assertion:1402:1407:6d4dcbfb8012669b138a3fd67c3b41460ced17e0008408c0b9d7c9f591cf2917", - "old_source_span": [ - 1402, - 1407 - ], - "old_content_sha256": "6d4dcbfb8012669b138a3fd67c3b41460ced17e0008408c0b9d7c9f591cf2917", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "invariant_category": "bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "old_assertion_id": "assertion:1415:1415:a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", - "old_source_span": [ - 1415, - 1415 - ], - "old_content_sha256": "a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "invariant_category": "bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "old_assertion_id": "assertion:1424:1424:c7598e5f87e2e832d39a203f626df63780e38526e411ceb322b4bbf7c063ff29", - "old_source_span": [ - 1424, - 1424 - ], - "old_content_sha256": "c7598e5f87e2e832d39a203f626df63780e38526e411ceb322b4bbf7c063ff29", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "invariant_category": "bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "old_assertion_id": "assertion:1425:1425:7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", - "old_source_span": [ - 1425, - 1425 - ], - "old_content_sha256": "7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "invariant_category": "bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", - "old_assertion_id": "assertion:1451:1451:a580a3e1405721e0a5eb3419522b1106915083e2aba73324140ffa0c39c0a637", - "old_source_span": [ - 1451, - 1451 - ], - "old_content_sha256": "a580a3e1405721e0a5eb3419522b1106915083e2aba73324140ffa0c39c0a637", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", - "invariant_category": "bootstrap_cli_rejects_arguments_without_echoing_them", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", - "old_assertion_id": "assertion:1452:1452:6dc7ff258b8274cbe231e06ab9d99722aa2e4eefc4bb3aec905ea73ec530f474", - "old_source_span": [ - 1452, - 1452 - ], - "old_content_sha256": "6dc7ff258b8274cbe231e06ab9d99722aa2e4eefc4bb3aec905ea73ec530f474", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_rejects_arguments_without_echoing_them", - "invariant_category": "bootstrap_cli_rejects_arguments_without_echoing_them", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", - "old_assertion_id": "assertion:1471:1471:a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", - "old_source_span": [ - 1471, - 1471 - ], - "old_content_sha256": "a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_interrupt", - "invariant_category": "bootstrap_cli_reports_interrupt", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", - "old_assertion_id": "assertion:1472:1472:145c4ca500b42a85a114e20e5dc2162706c8b809245b5875a9f0e83b187f6f06", - "old_source_span": [ - 1472, - 1472 - ], - "old_content_sha256": "145c4ca500b42a85a114e20e5dc2162706c8b809245b5875a9f0e83b187f6f06", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_interrupt", - "invariant_category": "bootstrap_cli_reports_interrupt", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", - "old_assertion_id": "assertion:1483:1483:a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", - "old_source_span": [ - 1483, - 1483 - ], - "old_content_sha256": "a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_pre_outcome_cleanup_failure", - "invariant_category": "bootstrap_cli_reports_pre_outcome_cleanup_failure", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - }, - { - "old_revision": "0e34911be4cdc25b3ec79dbcb097b62181958304", - "old_test_node": "tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure", - "old_assertion_id": "assertion:1484:1484:7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", - "old_source_span": [ - 1484, - 1484 - ], - "old_content_sha256": "7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1", - "new_test_node": "tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_pre_outcome_cleanup_failure", - "invariant_category": "bootstrap_cli_reports_pre_outcome_cleanup_failure", - "target_layer": "service", - "security_dimensions": { - "concurrency": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "lock_order": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "denial_side_effects": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "replay": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "revocation": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "evidence": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "transaction_ownership": { - "not_applicable_reason": "This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation." - }, - "concealment": "preserved" - } - } + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue","old_assertion_id":"assertion:1375:1375:e25f783cf32782e502386a114384abd167f7dc7e5c44aaa30cda41bc7d313e9f","old_source_span":[1375,1375],"old_content_sha256":"e25f783cf32782e502386a114384abd167f7dc7e5c44aaa30cda41bc7d313e9f","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue","invariant_category":"bootstrap_command_manifest_matches_the_active_catalogue","target_layer":"domain","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue","old_assertion_id":"assertion:1376:1376:8580c25b9d0e709842cf64b324bf13f09a0e8ab3c0655e17420fc005f94e2f82","old_source_span":[1376,1376],"old_content_sha256":"8580c25b9d0e709842cf64b324bf13f09a0e8ab3c0655e17420fc005f94e2f82","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue","invariant_category":"bootstrap_command_manifest_matches_the_active_catalogue","target_layer":"domain","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_command_manifest_matches_the_active_catalogue","old_assertion_id":"assertion:1377:1377:b2d1927409a59c144ee7a226736a7d1b35a993ce2a00e4879917d0d746d30812","old_source_span":[1377,1377],"old_content_sha256":"b2d1927409a59c144ee7a226736a7d1b35a993ce2a00e4879917d0d746d30812","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_command_manifest_matches_the_active_catalogue","invariant_category":"bootstrap_command_manifest_matches_the_active_catalogue","target_layer":"domain","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","old_assertion_id":"assertion:1387:1387:a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299","old_source_span":[1387,1387],"old_content_sha256":"a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","invariant_category":"bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","old_assertion_id":"assertion:1401:1401:ff5ee387d6f17cf2a9e6e9fb696a637d7d34613ea4b94bd8c2b3eb44918187e0","old_source_span":[1401,1401],"old_content_sha256":"ff5ee387d6f17cf2a9e6e9fb696a637d7d34613ea4b94bd8c2b3eb44918187e0","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","invariant_category":"bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","old_assertion_id":"assertion:1402:1407:6d4dcbfb8012669b138a3fd67c3b41460ced17e0008408c0b9d7c9f591cf2917","old_source_span":[1402,1407],"old_content_sha256":"6d4dcbfb8012669b138a3fd67c3b41460ced17e0008408c0b9d7c9f591cf2917","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","invariant_category":"bootstrap_cli_preserves_committed_outcome_when_engine_cleanup_fails","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","old_assertion_id":"assertion:1415:1415:a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299","old_source_span":[1415,1415],"old_content_sha256":"a771a4966bd0ddd1ddd5f6e2a5ab9c03ef1266eca9b2a52d9b08388f86578299","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","invariant_category":"bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","old_assertion_id":"assertion:1424:1424:c7598e5f87e2e832d39a203f626df63780e38526e411ceb322b4bbf7c063ff29","old_source_span":[1424,1424],"old_content_sha256":"c7598e5f87e2e832d39a203f626df63780e38526e411ceb322b4bbf7c063ff29","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","invariant_category":"bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","old_assertion_id":"assertion:1425:1425:7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1","old_source_span":[1425,1425],"old_content_sha256":"7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","invariant_category":"bootstrap_cli_does_not_relabel_internal_type_error_as_invalid_request","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_rejects_arguments_without_echoing_them","old_assertion_id":"assertion:1451:1451:a580a3e1405721e0a5eb3419522b1106915083e2aba73324140ffa0c39c0a637","old_source_span":[1451,1451],"old_content_sha256":"a580a3e1405721e0a5eb3419522b1106915083e2aba73324140ffa0c39c0a637","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_rejects_arguments_without_echoing_them","invariant_category":"bootstrap_cli_rejects_arguments_without_echoing_them","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_rejects_arguments_without_echoing_them","old_assertion_id":"assertion:1452:1452:6dc7ff258b8274cbe231e06ab9d99722aa2e4eefc4bb3aec905ea73ec530f474","old_source_span":[1452,1452],"old_content_sha256":"6dc7ff258b8274cbe231e06ab9d99722aa2e4eefc4bb3aec905ea73ec530f474","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_rejects_arguments_without_echoing_them","invariant_category":"bootstrap_cli_rejects_arguments_without_echoing_them","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure","old_assertion_id":"assertion:1471:1471:a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379","old_source_span":[1471,1471],"old_content_sha256":"a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_interrupt","invariant_category":"bootstrap_cli_reports_interrupt","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure","old_assertion_id":"assertion:1472:1472:145c4ca500b42a85a114e20e5dc2162706c8b809245b5875a9f0e83b187f6f06","old_source_span":[1472,1472],"old_content_sha256":"145c4ca500b42a85a114e20e5dc2162706c8b809245b5875a9f0e83b187f6f06","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_interrupt","invariant_category":"bootstrap_cli_reports_interrupt","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure","old_assertion_id":"assertion:1483:1483:a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379","old_source_span":[1483,1483],"old_content_sha256":"a20d21bd161d754f11ded53e59fbe467afaefa90a82265a3d3b3876cecd7d379","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_pre_outcome_cleanup_failure","invariant_category":"bootstrap_cli_reports_pre_outcome_cleanup_failure","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_bootstrap_cli_reports_interrupt_and_pre_outcome_cleanup_failure","old_assertion_id":"assertion:1484:1484:7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1","old_source_span":[1484,1484],"old_content_sha256":"7beba6e578a10575f63985aa6c9804d58d3185f40dff5f8b4d68c66f8f0226e1","new_test_node":"tests/authorization/admin_access/test_bootstrap_cli.py::test_bootstrap_cli_reports_pre_outcome_cleanup_failure","invariant_category":"bootstrap_cli_reports_pre_outcome_cleanup_failure","target_layer":"service","security_dimensions":{"concurrency":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"lock_order":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"denial_side_effects":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"replay":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"revocation":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"evidence":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"transaction_ownership":{"not_applicable_reason":"This command presentation assertion claims no database, concurrent session, durable replay or lifecycle mutation."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:449:449:f2883508da168dfdfd261b01116ea7df24470b8ee91619d980ab00d5d5427e4a","old_source_span":[449,449],"old_content_sha256":"f2883508da168dfdfd261b01116ea7df24470b8ee91619d980ab00d5d5427e4a","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:451:451:dd622b360791d8079bf844d484790199b8db37ee5ea285a329d16a4b21dbf784","old_source_span":[451,451],"old_content_sha256":"dd622b360791d8079bf844d484790199b8db37ee5ea285a329d16a4b21dbf784","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:452:452:33cdacf57f506a93a6aeed797a85295e6065084709111baaebaa8d49acba8064","old_source_span":[452,452],"old_content_sha256":"33cdacf57f506a93a6aeed797a85295e6065084709111baaebaa8d49acba8064","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:453:453:0f6fd12a0fec3986b552dcedefb0a0e2f016193ade41f0d59bb8d6c00a997ba3","old_source_span":[453,453],"old_content_sha256":"0f6fd12a0fec3986b552dcedefb0a0e2f016193ade41f0d59bb8d6c00a997ba3","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:454:454:892d69aa775bbae568ab95928afd3f2e8510473c81ecb97ced0362ba25a69ea4","old_source_span":[454,454],"old_content_sha256":"892d69aa775bbae568ab95928afd3f2e8510473c81ecb97ced0362ba25a69ea4","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:455:455:d6aafaee01d4c5d730b32404e4bf231b5292b5f1b87b1195441ffcc99bc39a85","old_source_span":[455,455],"old_content_sha256":"d6aafaee01d4c5d730b32404e4bf231b5292b5f1b87b1195441ffcc99bc39a85","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:465:465:e01f85bde248808173852c54d43b3f4ae3fe0ce2f923070c278d621d1609d361","old_source_span":[465,465],"old_content_sha256":"e01f85bde248808173852c54d43b3f4ae3fe0ce2f923070c278d621d1609d361","new_test_node":"tests/authorization/admin_access/test_api_journey.py::test_signed_admin_grant_journey","invariant_category":"signed_admin_grant_journey: Exact signed first-access and bootstrap setup is enforced by SignedAccess.actor and admin_access; the private target-row precondition also survives seed_read_target.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:466:466:cfe820fae89ab8e63939ce8d6baf0db2b00fad0c60630b9532cd44d653cb0873","old_source_span":[466,466],"old_content_sha256":"cfe820fae89ab8e63939ce8d6baf0db2b00fad0c60630b9532cd44d653cb0873","new_test_node":"tests/authorization/admin_access/test_api_journey.py::test_signed_admin_grant_journey","invariant_category":"signed_admin_grant_journey: Exact signed first-access and bootstrap setup is enforced by SignedAccess.actor and admin_access; the private target-row precondition also survives seed_read_target.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:475:475:ea67e112715430ba204987270b3ca99f4dbbc987a554f7fdebc92d3b2ef599e3","old_source_span":[475,475],"old_content_sha256":"ea67e112715430ba204987270b3ca99f4dbbc987a554f7fdebc92d3b2ef599e3","new_test_node":"tests/authorization/admin_access/test_bootstrap_postgresql.py::test_token_role_cannot_read_authorization_catalogue","invariant_category":"token_role_cannot_read_authorization_catalogue","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:476:476:ca6d82deaf94562de19e43d4b416bfa9479894f32d9a369ed4c251a3e657a136","old_source_span":[476,476],"old_content_sha256":"ca6d82deaf94562de19e43d4b416bfa9479894f32d9a369ed4c251a3e657a136","new_test_node":"tests/authorization/admin_access/test_bootstrap_postgresql.py::test_token_role_cannot_read_authorization_catalogue","invariant_category":"token_role_cannot_read_authorization_catalogue","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This token_role_cannot_read_authorization_catalogue assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:479:479:b21dbb094300c1bbf4facb38df7ac5d505a73c984bf8720ef993b05a61c55a24","old_source_span":[479,479],"old_content_sha256":"b21dbb094300c1bbf4facb38df7ac5d505a73c984bf8720ef993b05a61c55a24","new_test_node":"tests/authorization/admin_access/test_bootstrap_postgresql.py::test_bootstrap_dry_run_leaves_control_grants_and_events_unchanged","invariant_category":"bootstrap_dry_run_leaves_control_grants_and_events_unchanged","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:480:484:189fe26a3ff48ec7bafaf2569d7a0addca10f531b7437e179e6e15be76da1ecc","old_source_span":[480,484],"old_content_sha256":"189fe26a3ff48ec7bafaf2569d7a0addca10f531b7437e179e6e15be76da1ecc","new_test_node":"tests/authorization/admin_access/test_bootstrap_postgresql.py::test_bootstrap_dry_run_leaves_control_grants_and_events_unchanged","invariant_category":"bootstrap_dry_run_leaves_control_grants_and_events_unchanged","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This bootstrap_dry_run_leaves_control_grants_and_events_unchanged assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:487:487:6b10148444e271146b4366571898533c6696e42ae9d88a00e3ac9cdfaf06f3d1","old_source_span":[487,487],"old_content_sha256":"6b10148444e271146b4366571898533c6696e42ae9d88a00e3ac9cdfaf06f3d1","new_test_node":"tests/authorization/admin_access/test_api_journey.py::test_signed_admin_grant_journey","invariant_category":"signed_admin_grant_journey: Exact signed first-access and bootstrap setup is enforced by SignedAccess.actor and admin_access; the private target-row precondition also survives seed_read_target.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:488:493:d695235fa9173a1af3949656fa64442669daebe0cc7b75431468ce7caa036af6","old_source_span":[488,493],"old_content_sha256":"d695235fa9173a1af3949656fa64442669daebe0cc7b75431468ce7caa036af6","new_test_node":"tests/authorization/admin_access/test_api_journey.py::test_signed_admin_grant_journey","invariant_category":"signed_admin_grant_journey: Exact signed first-access and bootstrap setup is enforced by SignedAccess.actor and admin_access; the private target-row precondition also survives seed_read_target.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:495:495:3c382165686d6ab84661dfa18010521344a7ef167c2409b540f38d97e371967a","old_source_span":[495,495],"old_content_sha256":"3c382165686d6ab84661dfa18010521344a7ef167c2409b540f38d97e371967a","new_test_node":"tests/authorization/admin_access/test_bootstrap_postgresql.py::test_later_bootstrap_returns_audited_original_grant_conflict","invariant_category":"later_bootstrap_returns_audited_original_grant_conflict","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:496:501:404ebb42cbf4b82b56c3e7eb9783bd3c4d04c4dc909d4394b4430c2e606bcaf2","old_source_span":[496,501],"old_content_sha256":"404ebb42cbf4b82b56c3e7eb9783bd3c4d04c4dc909d4394b4430c2e606bcaf2","new_test_node":"tests/authorization/admin_access/test_bootstrap_postgresql.py::test_later_bootstrap_returns_audited_original_grant_conflict","invariant_category":"later_bootstrap_returns_audited_original_grant_conflict","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This later_bootstrap_returns_audited_original_grant_conflict assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:516:516:822c17aea19b206661b6240a71d76e3f2331c51038c8744fc3d559427addf04d","old_source_span":[516,516],"old_content_sha256":"822c17aea19b206661b6240a71d76e3f2331c51038c8744fc3d559427addf04d","new_test_node":"tests/authorization/admin_access/test_api_journey.py::test_signed_admin_grant_journey","invariant_category":"signed_admin_grant_journey: Exact signed first-access and bootstrap setup is enforced by SignedAccess.actor and admin_access; the private target-row precondition also survives seed_read_target.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This signed_admin_grant_journey assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:650:660:6ba1e51e42da41f79a93b3db3abe3d08091bd5cd651c51b5ba0881e36028dbdd","old_source_span":[650,660],"old_content_sha256":"6ba1e51e42da41f79a93b3db3abe3d08091bd5cd651c51b5ba0881e36028dbdd","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:661:661:c921d096efe8fe11923e30ecb3e32a6e364a603301c56dddb4591b143bab29e8","old_source_span":[661,661],"old_content_sha256":"c921d096efe8fe11923e30ecb3e32a6e364a603301c56dddb4591b143bab29e8","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:662:662:c5ca383abed0194b781a51d3c81d5b9fc998cf2b300c876c36402c98879e418f","old_source_span":[662,662],"old_content_sha256":"c5ca383abed0194b781a51d3c81d5b9fc998cf2b300c876c36402c98879e418f","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:663:663:1ef752014c9f4bf515713dcd16ae2dbfb98505bfdc05c0a05216726622edc92e","old_source_span":[663,663],"old_content_sha256":"1ef752014c9f4bf515713dcd16ae2dbfb98505bfdc05c0a05216726622edc92e","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:664:664:722ee5d1439269f179e8e9e65d2b27d5254a6a3eb2447593d2bdbaf4f0b87f5b","old_source_span":[664,664],"old_content_sha256":"722ee5d1439269f179e8e9e65d2b27d5254a6a3eb2447593d2bdbaf4f0b87f5b","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:665:665:f951850b6a71b1e970721c3702de92295bef16b59f42ee13e79eb87ccd01f0f9","old_source_span":[665,665],"old_content_sha256":"f951850b6a71b1e970721c3702de92295bef16b59f42ee13e79eb87ccd01f0f9","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:666:668:019ca44ba3c0bc7b0f2f76dc75b17ac1c7c92602ed7d7d12bef61adeb7e1ba46","old_source_span":[666,668],"old_content_sha256":"019ca44ba3c0bc7b0f2f76dc75b17ac1c7c92602ed7d7d12bef61adeb7e1ba46","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:669:669:0322c3eeae44e746787dd01c65ea7247e01913cbdc0dcf9845527b7e4a749631","old_source_span":[669,669],"old_content_sha256":"0322c3eeae44e746787dd01c65ea7247e01913cbdc0dcf9845527b7e4a749631","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:670:670:7d61ec6cc0e367859795765544f4210adc060ba54f3ddbe618cbbb392f1e0d98","old_source_span":[670,670],"old_content_sha256":"7d61ec6cc0e367859795765544f4210adc060ba54f3ddbe618cbbb392f1e0d98","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:671:671:9eb16a419320d1caa0835f08f5c2c2325545c982b7d778dc5e02303e7a6a2d85","old_source_span":[671,671],"old_content_sha256":"9eb16a419320d1caa0835f08f5c2c2325545c982b7d778dc5e02303e7a6a2d85","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:672:672:7f4193c2882c0b788119813917150d3ef5be689674b00257523d2acc967221cd","old_source_span":[672,672],"old_content_sha256":"7f4193c2882c0b788119813917150d3ef5be689674b00257523d2acc967221cd","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:697:697:c1847e1cf5e04a0c18d3ff9b2dfe6dc4b29bb6ab38be055774c52a1f318ab0e9","old_source_span":[697,697],"old_content_sha256":"c1847e1cf5e04a0c18d3ff9b2dfe6dc4b29bb6ab38be055774c52a1f318ab0e9","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:698:698:b902fcf6126983735da7189fd1dda1b457ccdcdec937b0c9f1e33fde607289e5","old_source_span":[698,698],"old_content_sha256":"b902fcf6126983735da7189fd1dda1b457ccdcdec937b0c9f1e33fde607289e5","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_projects_only_public_fields","invariant_category":"admin_read_projects_only_public_fields: Six original cases: human-profile, human-link, service-profile, service-link, suspended-profile, revoked_link-link; independent fresh rows, no reset with disabled triggers.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_read_projects_only_public_fields assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:699:699:23b806da5e9adc08e3e251f6052fdeda81838949fd93c5199247b1a6c4329aee","old_source_span":[699,699],"old_content_sha256":"23b806da5e9adc08e3e251f6052fdeda81838949fd93c5199247b1a6c4329aee","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_touches_caller_not_target","invariant_category":"admin_read_touches_caller_not_target: Profile and link independently preserve caller-only observation.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:701:701:9f75f8db8ab9bbf0d371f9446a84fc5d8f95193ad0ad3d49839f6c29ab49f6b8","old_source_span":[701,701],"old_content_sha256":"9f75f8db8ab9bbf0d371f9446a84fc5d8f95193ad0ad3d49839f6c29ab49f6b8","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_touches_caller_not_target","invariant_category":"admin_read_touches_caller_not_target: Profile and link independently preserve caller-only observation.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:702:702:19ec1189de9d16957dcbda49d41c74ddab894edd4a41ff5316c6af6d29f952bf","old_source_span":[702,702],"old_content_sha256":"19ec1189de9d16957dcbda49d41c74ddab894edd4a41ff5316c6af6d29f952bf","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_touches_caller_not_target","invariant_category":"admin_read_touches_caller_not_target: Profile and link independently preserve caller-only observation.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_touches_caller_not_target assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:716:716:0f50b69f71e66eb740e41e7da4e60898815c27d9738b7b2f9663723656ea4d25","old_source_span":[716,716],"old_content_sha256":"0f50b69f71e66eb740e41e7da4e60898815c27d9738b7b2f9663723656ea4d25","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:721:721:1f0de5090a19771d5a0deb454942f0cdf1d8929f69650e5ed7fb3bec8a11d0a8","old_source_span":[721,721],"old_content_sha256":"1f0de5090a19771d5a0deb454942f0cdf1d8929f69650e5ed7fb3bec8a11d0a8","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:724:724:6af90ae0b59189077e2983931e847be4a53ea612de636c8dca4109b847eb18de","old_source_span":[724,724],"old_content_sha256":"6af90ae0b59189077e2983931e847be4a53ea612de636c8dca4109b847eb18de","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:725:725:8ea661df2d070d4f7f2dea9db5032b28c17589e4a5360a6e009e6f3f58c7386e","old_source_span":[725,725],"old_content_sha256":"8ea661df2d070d4f7f2dea9db5032b28c17589e4a5360a6e009e6f3f58c7386e","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:726:726:51d116ae60491771e740b6407ea504388a6af4fc14abe8b81061b6c900bb268c","old_source_span":[726,726],"old_content_sha256":"51d116ae60491771e740b6407ea504388a6af4fc14abe8b81061b6c900bb268c","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:727:727:1895d9018072803fac7d726048e98198ceaf764ef4c21b32f7a254058884ae6b","old_source_span":[727,727],"old_content_sha256":"1895d9018072803fac7d726048e98198ceaf764ef4c21b32f7a254058884ae6b","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:728:728:2ef4fb04396a58db847a21c5b718d817ba5848bf581556631f13bb10562919b5","old_source_span":[728,728],"old_content_sha256":"2ef4fb04396a58db847a21c5b718d817ba5848bf581556631f13bb10562919b5","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:729:729:6e812b708dfc68edfe7c26d29a4039d581ad063ee6b276249a3bdbccb0a45869","old_source_span":[729,729],"old_content_sha256":"6e812b708dfc68edfe7c26d29a4039d581ad063ee6b276249a3bdbccb0a45869","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:730:730:1fcc9824235dc27cf9f7d9e99166564ed39a05377a6709185b95d09e7354d1c8","old_source_span":[730,730],"old_content_sha256":"1fcc9824235dc27cf9f7d9e99166564ed39a05377a6709185b95d09e7354d1c8","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:731:731:150a5109fca5ca330be8deb7e1ab3abb835fc0292b5e1f06c24396fa515904c9","old_source_span":[731,731],"old_content_sha256":"150a5109fca5ca330be8deb7e1ab3abb835fc0292b5e1f06c24396fa515904c9","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:732:734:cc0891889212c51f04b6d0fff7deacb1f8e9d541a0a4dce7c599aa1626b456e6","old_source_span":[732,734],"old_content_sha256":"cc0891889212c51f04b6d0fff7deacb1f8e9d541a0a4dce7c599aa1626b456e6","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_read_records_exact_authorization_provenance","invariant_category":"admin_read_records_exact_authorization_provenance: Profile/link each assert exactly one correctly scoped event rather than two events from a shared history.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_records_exact_authorization_provenance assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:757:757:21cf714396c759148e7818d43bee1c2c64ea856a1eb024bde1d1a614e29157f2","old_source_span":[757,757],"old_content_sha256":"21cf714396c759148e7818d43bee1c2c64ea856a1eb024bde1d1a614e29157f2","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:759:759:2a1deee35cfba7c2bd87d8962dbd1185c1042ec7ae3de385b612ab971f590886","old_source_span":[759,759],"old_content_sha256":"2a1deee35cfba7c2bd87d8962dbd1185c1042ec7ae3de385b612ab971f590886","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:760:760:a6ef5d647572c9bd146921e0617013c31725456007036543fbe200e1895aa58f","old_source_span":[760,760],"old_content_sha256":"a6ef5d647572c9bd146921e0617013c31725456007036543fbe200e1895aa58f","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:761:761:1f80f9411c220efc2642c84f6fc7199b92a7efed20e838bc9c63d735c6381a3c","old_source_span":[761,761],"old_content_sha256":"1f80f9411c220efc2642c84f6fc7199b92a7efed20e838bc9c63d735c6381a3c","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:762:762:13c94f51eb0d021e3afb98d6f2229f49ed7c480a9790d44c6e554e96e518f677","old_source_span":[762,762],"old_content_sha256":"13c94f51eb0d021e3afb98d6f2229f49ed7c480a9790d44c6e554e96e518f677","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:763:763:9d8575e2f089997ea44c0b85a5ec02f90521be68b56c4452cde0b9ceb98f9ddf","old_source_span":[763,763],"old_content_sha256":"9d8575e2f089997ea44c0b85a5ec02f90521be68b56c4452cde0b9ceb98f9ddf","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:765:765:be07554e5986a146910cda46714983c771fd69fa92b7c367917429842d82758a","old_source_span":[765,765],"old_content_sha256":"be07554e5986a146910cda46714983c771fd69fa92b7c367917429842d82758a","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:766:766:3f69901de2c93b2810ffc9c5b875466b7b91c0407cee8a1d7be050c60c6d160e","old_source_span":[766,766],"old_content_sha256":"3f69901de2c93b2810ffc9c5b875466b7b91c0407cee8a1d7be050c60c6d160e","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_profile_read_returns_committed_observation","invariant_category":"self_admin_profile_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_profile_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:774:774:e26eaad2408b629e6e4d5bb4d383e268067009977a66fb783fc8c2758d52ae16","old_source_span":[774,774],"old_content_sha256":"e26eaad2408b629e6e4d5bb4d383e268067009977a66fb783fc8c2758d52ae16","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_link_read_returns_committed_observation","invariant_category":"self_admin_link_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:776:776:c7edd2abb7af66828003b399f9311e0ef72833da03075186a6297efdab90ffb6","old_source_span":[776,776],"old_content_sha256":"c7edd2abb7af66828003b399f9311e0ef72833da03075186a6297efdab90ffb6","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_link_read_returns_committed_observation","invariant_category":"self_admin_link_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:777:777:85ec48f36984268aed4eb76fbfbc5f61a7b91fae136a6110fc680caf9e9b3af1","old_source_span":[777,777],"old_content_sha256":"85ec48f36984268aed4eb76fbfbc5f61a7b91fae136a6110fc680caf9e9b3af1","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_link_read_returns_committed_observation","invariant_category":"self_admin_link_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:778:778:0dea4f5e176b8b4bc76c0bf3ccee6f0ca4a5970d54eeab57c2840a8339cd1245","old_source_span":[778,778],"old_content_sha256":"0dea4f5e176b8b4bc76c0bf3ccee6f0ca4a5970d54eeab57c2840a8339cd1245","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_link_read_returns_committed_observation","invariant_category":"self_admin_link_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:779:779:6b2458c85428b5e509b3dc3d47c50f219549862347bbee21cf3eaadb1bed14b8","old_source_span":[779,779],"old_content_sha256":"6b2458c85428b5e509b3dc3d47c50f219549862347bbee21cf3eaadb1bed14b8","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_link_read_returns_committed_observation","invariant_category":"self_admin_link_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:781:781:332b106d364456261bcada494d2d8b87f580d35cfe47b24809c39c5cf7521cd7","old_source_span":[781,781],"old_content_sha256":"332b106d364456261bcada494d2d8b87f580d35cfe47b24809c39c5cf7521cd7","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_link_read_returns_committed_observation","invariant_category":"self_admin_link_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:782:782:53989a216d8746a0964955d5ad057c3a39a0967d7e929cf407a89fb08c876d22","old_source_span":[782,782],"old_content_sha256":"53989a216d8746a0964955d5ad057c3a39a0967d7e929cf407a89fb08c876d22","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_self_admin_link_read_returns_committed_observation","invariant_category":"self_admin_link_read_returns_committed_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This self_admin_link_read_returns_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:795:795:754c42d827b3cca8f25510279956a678bfd491c421caec14368d467772cd0b56","old_source_span":[795,795],"old_content_sha256":"754c42d827b3cca8f25510279956a678bfd491c421caec14368d467772cd0b56","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_missing_admin_target_has_concealed_response_and_no_success_effect","invariant_category":"missing_admin_target_has_concealed_response_and_no_success_effect","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:801:801:9c206c2d04b92937e5a5797db626eef3c7eb1b1c297273efd06adabd87e40e0f","old_source_span":[801,801],"old_content_sha256":"9c206c2d04b92937e5a5797db626eef3c7eb1b1c297273efd06adabd87e40e0f","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_missing_admin_target_has_concealed_response_and_no_success_effect","invariant_category":"missing_admin_target_has_concealed_response_and_no_success_effect","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:802:802:2042091a703872cc506155e1d6ff840c8a7aad15b5b41e99add9b0d90f84bceb","old_source_span":[802,802],"old_content_sha256":"2042091a703872cc506155e1d6ff840c8a7aad15b5b41e99add9b0d90f84bceb","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_missing_admin_target_has_concealed_response_and_no_success_effect","invariant_category":"missing_admin_target_has_concealed_response_and_no_success_effect","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:803:803:0482f26f6cb4ed8cd95ecde5b8e07d8b6b54b601934f7eaf8e81832d5f33527e","old_source_span":[803,803],"old_content_sha256":"0482f26f6cb4ed8cd95ecde5b8e07d8b6b54b601934f7eaf8e81832d5f33527e","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_missing_admin_target_has_concealed_response_and_no_success_effect","invariant_category":"missing_admin_target_has_concealed_response_and_no_success_effect","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:804:804:c66845889ab64499043a9d977e5380060a13cbb1dd1f310a0e53bb9eb48d152a","old_source_span":[804,804],"old_content_sha256":"c66845889ab64499043a9d977e5380060a13cbb1dd1f310a0e53bb9eb48d152a","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_missing_admin_target_has_concealed_response_and_no_success_effect","invariant_category":"missing_admin_target_has_concealed_response_and_no_success_effect","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This missing_admin_target_has_concealed_response_and_no_success_effect assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:811:811:b0242ba2dc8ce2d9a0e8ef8e0a0aece5fd9e41b9326c8843d411e4cafc2aefa0","old_source_span":[811,811],"old_content_sha256":"b0242ba2dc8ce2d9a0e8ef8e0a0aece5fd9e41b9326c8843d411e4cafc2aefa0","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:812:812:21a8e9a96d3870167d8d9d93cb4a56b8c2937a292880f7e58e6b3ce1ef51b35f","old_source_span":[812,812],"old_content_sha256":"21a8e9a96d3870167d8d9d93cb4a56b8c2937a292880f7e58e6b3ce1ef51b35f","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_read_failure_rolls_back_staged_effects","invariant_category":"admin_read_failure_rolls_back_staged_effects: Both read surfaces; evidence, lookup, touch, commit faults. Shared bounded-error assertions remain in assert_unavailable and every failure test calls it.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_read_failure_rolls_back_staged_effects assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:845:845:eeee8063b24fc488d4a5094c6b98fb1672ba6ce8d7c81a73a2178fbb8930db1b","old_source_span":[845,845],"old_content_sha256":"eeee8063b24fc488d4a5094c6b98fb1672ba6ce8d7c81a73a2178fbb8930db1b","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_catalogue_read_commit_failure_rolls_back_observation","invariant_category":"catalogue_read_commit_failure_rolls_back_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This catalogue_read_commit_failure_rolls_back_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This catalogue_read_commit_failure_rolls_back_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This catalogue_read_commit_failure_rolls_back_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This catalogue_read_commit_failure_rolls_back_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:855:855:5b4aec28744287c349e3624609d3563253e94d7bfcde1a2ea3527c7c3d254472","old_source_span":[855,855],"old_content_sha256":"5b4aec28744287c349e3624609d3563253e94d7bfcde1a2ea3527c7c3d254472","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_catalogue_read_returns_public_definitions","invariant_category":"admin_catalogue_read_returns_public_definitions: Permissions and definitions are independent public catalogue projections, retaining 73/5 and exact role ordering.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:856:856:09089a7a4e5c14284657e3a9ed3322405e23d7999f388a4cef8987a3e948a878","old_source_span":[856,856],"old_content_sha256":"09089a7a4e5c14284657e3a9ed3322405e23d7999f388a4cef8987a3e948a878","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_catalogue_read_returns_public_definitions","invariant_category":"admin_catalogue_read_returns_public_definitions: Permissions and definitions are independent public catalogue projections, retaining 73/5 and exact role ordering.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:857:857:a2b5518ab339581a767646a1752b545816258acd24165db4135c27627ca2e7c5","old_source_span":[857,857],"old_content_sha256":"a2b5518ab339581a767646a1752b545816258acd24165db4135c27627ca2e7c5","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_catalogue_read_returns_public_definitions","invariant_category":"admin_catalogue_read_returns_public_definitions: Permissions and definitions are independent public catalogue projections, retaining 73/5 and exact role ordering.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:858:864:93738607697df4410c4ca1b1427878adb3bd1c1683dc0d92978829c710f67a3d","old_source_span":[858,864],"old_content_sha256":"93738607697df4410c4ca1b1427878adb3bd1c1683dc0d92978829c710f67a3d","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_catalogue_read_returns_public_definitions","invariant_category":"admin_catalogue_read_returns_public_definitions: Permissions and definitions are independent public catalogue projections, retaining 73/5 and exact role ordering.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:866:866:bf7f3d2a7ec4d62de58f8ad784fff11575c2e63c22d9cdb281a5231804be6aea","old_source_span":[866,866],"old_content_sha256":"bf7f3d2a7ec4d62de58f8ad784fff11575c2e63c22d9cdb281a5231804be6aea","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_catalogue_read_returns_public_definitions","invariant_category":"admin_catalogue_read_returns_public_definitions: Permissions and definitions are independent public catalogue projections, retaining 73/5 and exact role ordering.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:867:867:a86b1c269a29a76ecdc1eba59482ed6852b6af82707b68d4055a87945e1ebc33","old_source_span":[867,867],"old_content_sha256":"a86b1c269a29a76ecdc1eba59482ed6852b6af82707b68d4055a87945e1ebc33","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_catalogue_read_returns_public_definitions","invariant_category":"admin_catalogue_read_returns_public_definitions: Permissions and definitions are independent public catalogue projections, retaining 73/5 and exact role ordering.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_catalogue_read_returns_public_definitions assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:876:876:fdbc4f27e14d56258281c470a4bf726d690f843c1d2dffcc5b8a93fb8be3fe59","old_source_span":[876,876],"old_content_sha256":"fdbc4f27e14d56258281c470a4bf726d690f843c1d2dffcc5b8a93fb8be3fe59","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_admin_self_patch_commit_failure_rolls_back","invariant_category":"admin_self_patch_commit_failure_rolls_back","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_self_patch_commit_failure_rolls_back assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_self_patch_commit_failure_rolls_back assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_self_patch_commit_failure_rolls_back assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_self_patch_commit_failure_rolls_back assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_self_patch_commit_failure_rolls_back assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:882:882:adf6a00fd60ee2976c7e4f1ee857615657d9c38ac25fe497a1852351fa89a7d8","old_source_span":[882,882],"old_content_sha256":"adf6a00fd60ee2976c7e4f1ee857615657d9c38ac25fe497a1852351fa89a7d8","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_self_patch_commits_requested_observation","invariant_category":"admin_self_patch_commits_requested_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:884:884:9664b51b24741dac59f7892a2282b46f5ad8f77372a1e505b754b3edc23bf674","old_source_span":[884,884],"old_content_sha256":"9664b51b24741dac59f7892a2282b46f5ad8f77372a1e505b754b3edc23bf674","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_self_patch_commits_requested_observation","invariant_category":"admin_self_patch_commits_requested_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:885:885:6e52a0ca56af4a006b75afd85f264c6b4d3f8306bd1059433f8fdb0af393c145","old_source_span":[885,885],"old_content_sha256":"6e52a0ca56af4a006b75afd85f264c6b4d3f8306bd1059433f8fdb0af393c145","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_self_patch_commits_requested_observation","invariant_category":"admin_self_patch_commits_requested_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:886:886:cda9a83e3087eb68d609a1e0f10955716abd3b6f7ac31d5225a155d2d82d8911","old_source_span":[886,886],"old_content_sha256":"cda9a83e3087eb68d609a1e0f10955716abd3b6f7ac31d5225a155d2d82d8911","new_test_node":"tests/authorization/admin_access/test_admin_reads_postgresql.py::test_admin_self_patch_commits_requested_observation","invariant_category":"admin_self_patch_commits_requested_observation","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_self_patch_commits_requested_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:932:932:850bc40502d797cc1a5124c97b2984fda216c7afc08424bbe0c261874afc5967","old_source_span":[932,932],"old_content_sha256":"850bc40502d797cc1a5124c97b2984fda216c7afc08424bbe0c261874afc5967","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_self_admin_grant_is_denied_without_grant","invariant_category":"self_admin_grant_is_denied_without_grant","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:933:933:b473807e5c1e5369ea7b04af78e7d170d3ab7b8412d87e2420fafd36b5ad2c4d","old_source_span":[933,933],"old_content_sha256":"b473807e5c1e5369ea7b04af78e7d170d3ab7b8412d87e2420fafd36b5ad2c4d","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_self_admin_grant_is_denied_without_grant","invariant_category":"self_admin_grant_is_denied_without_grant","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This self_admin_grant_is_denied_without_grant assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:934:934:8fca91ca35d6c787fbddeb66b17908a61bfc772bca6239dc8e2533d77ad488f2","old_source_span":[934,934],"old_content_sha256":"8fca91ca35d6c787fbddeb66b17908a61bfc772bca6239dc8e2533d77ad488f2","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:935:935:d06760e4a6b4972e150a4b3a80fc5b2dd5353178c662baafd980c1db2af0ac01","old_source_span":[935,935],"old_content_sha256":"d06760e4a6b4972e150a4b3a80fc5b2dd5353178c662baafd980c1db2af0ac01","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:936:936:93d2301ea6a234bc395cd2f0d56b75d40fa43d62ff23e2f7aa84038c31218207","old_source_span":[936,936],"old_content_sha256":"93d2301ea6a234bc395cd2f0d56b75d40fa43d62ff23e2f7aa84038c31218207","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:937:937:6003d54406e889b9cb8f7ec9c9dfd415fae8a6a455a60f8e80d9a1d6aa06ae8e","old_source_span":[937,937],"old_content_sha256":"6003d54406e889b9cb8f7ec9c9dfd415fae8a6a455a60f8e80d9a1d6aa06ae8e","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:938:938:f609e13770b149cb735476fac200f43e4746ace1ead880864b93c0733f9b7842","old_source_span":[938,938],"old_content_sha256":"f609e13770b149cb735476fac200f43e4746ace1ead880864b93c0733f9b7842","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_ineligible_grant_targets_share_missing_response","invariant_category":"ineligible_grant_targets_share_missing_response: Service, suspended profile and revoked/no-active-link each compared to truly absent actor; valid control row retained; exact bounded message retained.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:939:939:2db93e64eafd868b47a9f1cc77173fb3cfa6b54563304188ab26caeca46117cf","old_source_span":[939,939],"old_content_sha256":"2db93e64eafd868b47a9f1cc77173fb3cfa6b54563304188ab26caeca46117cf","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_ineligible_grant_targets_share_missing_response","invariant_category":"ineligible_grant_targets_share_missing_response: Service, suspended profile and revoked/no-active-link each compared to truly absent actor; valid control row retained; exact bounded message retained.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:955:955:b73ab35cadb31f3a9a98fa699cf945db34f564e7a9fbf3c7304429b65ba76561","old_source_span":[955,955],"old_content_sha256":"b73ab35cadb31f3a9a98fa699cf945db34f564e7a9fbf3c7304429b65ba76561","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_ineligible_grant_targets_share_missing_response","invariant_category":"ineligible_grant_targets_share_missing_response: Service, suspended profile and revoked/no-active-link each compared to truly absent actor; valid control row retained; exact bounded message retained.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:956:964:1f7c7a1170480d80c56252a8bab20eaaa8483e23bc24caa882be598ad6da1357","old_source_span":[956,964],"old_content_sha256":"1f7c7a1170480d80c56252a8bab20eaaa8483e23bc24caa882be598ad6da1357","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_ineligible_grant_targets_share_missing_response","invariant_category":"ineligible_grant_targets_share_missing_response: Service, suspended profile and revoked/no-active-link each compared to truly absent actor; valid control row retained; exact bounded message retained.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This ineligible_grant_targets_share_missing_response assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1038:1038:f40dfd33414f4e761658b5cf6d8a037d0db1b3e325758e9d5aa00011e5503ed1","old_source_span":[1038,1038],"old_content_sha256":"f40dfd33414f4e761658b5cf6d8a037d0db1b3e325758e9d5aa00011e5503ed1","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1039:1041:7dd0da7be985ad011fbac1eb4a5fa3a5e472e7a6274cf3fbf7461ec4c685b183","old_source_span":[1039,1041],"old_content_sha256":"7dd0da7be985ad011fbac1eb4a5fa3a5e472e7a6274cf3fbf7461ec4c685b183","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1054:1054:40769584d2bfc72c72a93973b57f51c2be20e9c125f6e588a79c379f559c0ddb","old_source_span":[1054,1054],"old_content_sha256":"40769584d2bfc72c72a93973b57f51c2be20e9c125f6e588a79c379f559c0ddb","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1055:1055:bad195d89e57ae42d85585e34201dd8425731603545913b2258cbb9091d59e0f","old_source_span":[1055,1055],"old_content_sha256":"bad195d89e57ae42d85585e34201dd8425731603545913b2258cbb9091d59e0f","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1072:1072:4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","old_source_span":[1072,1072],"old_content_sha256":"4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Project-manager/project and audit-authority/project issue cases retain exact success and linked invalidation; also operator/system and audit-authority/system.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1108:1108:034d7897f667679f0120ada386fbf47c791a367c35e6f393c7c86b386f12d604","old_source_span":[1108,1108],"old_content_sha256":"034d7897f667679f0120ada386fbf47c791a367c35e6f393c7c86b386f12d604","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1109:1109:feab52ff800fb39ff981a78ec906b50ecb426a64e86ed84ca08e5e3f8ef93037","old_source_span":[1109,1109],"old_content_sha256":"feab52ff800fb39ff981a78ec906b50ecb426a64e86ed84ca08e5e3f8ef93037","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1110:1112:c8b46ee214f2cae19885f9f570441b18fad7eedd8010539c2ca297af5c3c7d5d","old_source_span":[1110,1112],"old_content_sha256":"c8b46ee214f2cae19885f9f570441b18fad7eedd8010539c2ca297af5c3c7d5d","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1113:1113:4618b4ae7ef773144c83de94518fd041b45aafbae43d0d9893322b3f3a3ed7c6","old_source_span":[1113,1113],"old_content_sha256":"4618b4ae7ef773144c83de94518fd041b45aafbae43d0d9893322b3f3a3ed7c6","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1115:1115:480014ecd7db66a3767ce3ace3327ad8d5b2a8ed552b56fb748ddc7521aef558","old_source_span":[1115,1115],"old_content_sha256":"480014ecd7db66a3767ce3ace3327ad8d5b2a8ed552b56fb748ddc7521aef558","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1116:1116:6dffe6474ad1b8b6c45cf05bc830c4ec2c4bfa27e925a7284a6886f71b4f1575","old_source_span":[1116,1116],"old_content_sha256":"6dffe6474ad1b8b6c45cf05bc830c4ec2c4bfa27e925a7284a6886f71b4f1575","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1117:1117:727012c3b70c439ff4c6db99ca9daff244180a8211c482ab475141aeb9dc0363","old_source_span":[1117,1117],"old_content_sha256":"727012c3b70c439ff4c6db99ca9daff244180a8211c482ab475141aeb9dc0363","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1118:1118:113cb589cb26dcb5d2e1c83d9bceca4520d11ad02ea1f4b84391466fa9fbc225","old_source_span":[1118,1118],"old_content_sha256":"113cb589cb26dcb5d2e1c83d9bceca4520d11ad02ea1f4b84391466fa9fbc225","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_audit_authority_cannot_issue_grant","invariant_category":"audit_authority_cannot_issue_grant","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This audit_authority_cannot_issue_grant assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This audit_authority_cannot_issue_grant assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This audit_authority_cannot_issue_grant assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This audit_authority_cannot_issue_grant assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This audit_authority_cannot_issue_grant assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This audit_authority_cannot_issue_grant assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This audit_authority_cannot_issue_grant assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1119:1119:57da5107292462d4ab545c35bae4c8a4723bede25005b4843d94583dda7bbc7d","old_source_span":[1119,1119],"old_content_sha256":"57da5107292462d4ab545c35bae4c8a4723bede25005b4843d94583dda7bbc7d","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1120:1120:13baf52652ac90e57d10755c61835d8756eaff650de2e85941d3e926a0c85a24","old_source_span":[1120,1120],"old_content_sha256":"13baf52652ac90e57d10755c61835d8756eaff650de2e85941d3e926a0c85a24","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1121:1121:52330f38b4ebc6dd2d751362fd58220c65fdc55943341a55378f3ad5b0a0f10b","old_source_span":[1121,1121],"old_content_sha256":"52330f38b4ebc6dd2d751362fd58220c65fdc55943341a55378f3ad5b0a0f10b","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_project_auditor_reads_only_granted_project","invariant_category":"project_auditor_reads_only_granted_project: Independent list/history/foreign/profile/link cases. The mutation half of old combined status assertion is separately preserved by test_audit_authority_cannot_issue_grant.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This project_auditor_reads_only_granted_project assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1134:1134:8f5232c8631454e2f0dca06f26918427efa912ec32270f1e6e426684386be73a","old_source_span":[1134,1134],"old_content_sha256":"8f5232c8631454e2f0dca06f26918427efa912ec32270f1e6e426684386be73a","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_system_auditor_has_exact_read_surface","invariant_category":"system_auditor_has_exact_read_surface: Six routes: permissions/definitions/list/history/profile/link. Actual system-auditor setup, exact row IDs and 73/5/2/1 totals; no project grant needed for system scope.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1157:1157:43d27bc6ed654b8de9d8c042e8dce5131272ffdadedd2befc6498464bfcd72ea","old_source_span":[1157,1157],"old_content_sha256":"43d27bc6ed654b8de9d8c042e8dce5131272ffdadedd2befc6498464bfcd72ea","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_system_auditor_has_exact_read_surface","invariant_category":"system_auditor_has_exact_read_surface: Six routes: permissions/definitions/list/history/profile/link. Actual system-auditor setup, exact row IDs and 73/5/2/1 totals; no project grant needed for system scope.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1158:1158:fc05ebff793da0171bc96b57ed638ca4ba6cf20a97c032d5db3135f556a6b7ef","old_source_span":[1158,1158],"old_content_sha256":"fc05ebff793da0171bc96b57ed638ca4ba6cf20a97c032d5db3135f556a6b7ef","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_system_auditor_has_exact_read_surface","invariant_category":"system_auditor_has_exact_read_surface: Six routes: permissions/definitions/list/history/profile/link. Actual system-auditor setup, exact row IDs and 73/5/2/1 totals; no project grant needed for system scope.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1159:1159:cd95151abea955faa9cabddac1ae9c7e1bb361dad3c31792c8a60d363f744287","old_source_span":[1159,1159],"old_content_sha256":"cd95151abea955faa9cabddac1ae9c7e1bb361dad3c31792c8a60d363f744287","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_system_auditor_has_exact_read_surface","invariant_category":"system_auditor_has_exact_read_surface: Six routes: permissions/definitions/list/history/profile/link. Actual system-auditor setup, exact row IDs and 73/5/2/1 totals; no project grant needed for system scope.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1160:1160:7d18fe896d59f2ec54a2dd3ccfcbf6c17fd933145512ac3beb1e294f1ac56864","old_source_span":[1160,1160],"old_content_sha256":"7d18fe896d59f2ec54a2dd3ccfcbf6c17fd933145512ac3beb1e294f1ac56864","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_system_auditor_has_exact_read_surface","invariant_category":"system_auditor_has_exact_read_surface: Six routes: permissions/definitions/list/history/profile/link. Actual system-auditor setup, exact row IDs and 73/5/2/1 totals; no project grant needed for system scope.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1161:1161:e0f1ab7e03f9e61ea88d6ae9d018861422eace089435c55167f1fa3d06e6dd5f","old_source_span":[1161,1161],"old_content_sha256":"e0f1ab7e03f9e61ea88d6ae9d018861422eace089435c55167f1fa3d06e6dd5f","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_system_auditor_has_exact_read_surface","invariant_category":"system_auditor_has_exact_read_surface: Six routes: permissions/definitions/list/history/profile/link. Actual system-auditor setup, exact row IDs and 73/5/2/1 totals; no project grant needed for system scope.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This system_auditor_has_exact_read_surface assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1180:1180:891da1f9e3b855ede686353b6642d3be57f4af8dcf18fac9b4ef90da5bb4054f","old_source_span":[1180,1180],"old_content_sha256":"891da1f9e3b855ede686353b6642d3be57f4af8dcf18fac9b4ef90da5bb4054f","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_grant_mutation_commit_failure_rolls_back","invariant_category":"grant_mutation_commit_failure_rolls_back: Issue and revoke independently stage actual product/evidence before fault, roll back, then retry the same key.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1181:1181:95c4b990778ea7e58dd8450e6d2583e722add8bebfe6e44f8cb164a051b169d0","old_source_span":[1181,1181],"old_content_sha256":"95c4b990778ea7e58dd8450e6d2583e722add8bebfe6e44f8cb164a051b169d0","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_grant_mutation_commit_failure_rolls_back","invariant_category":"grant_mutation_commit_failure_rolls_back: Issue and revoke independently stage actual product/evidence before fault, roll back, then retry the same key.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1188:1188:1c2561d9112367ce18a15588d520ecb463e1822ef09c165089207359d084a01f","old_source_span":[1188,1188],"old_content_sha256":"1c2561d9112367ce18a15588d520ecb463e1822ef09c165089207359d084a01f","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1189:1189:693816100a32694fef179a44b661f74a73615ebceb75befe1141f92463bcac0d","old_source_span":[1189,1189],"old_content_sha256":"693816100a32694fef179a44b661f74a73615ebceb75befe1141f92463bcac0d","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1195:1195:daaac5ad8c375e0fdf2ca33f37dcfe8810e49762af09142a8889cb4a976f8bff","old_source_span":[1195,1195],"old_content_sha256":"daaac5ad8c375e0fdf2ca33f37dcfe8810e49762af09142a8889cb4a976f8bff","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1196:1196:d16e602395b34a3cd4e40acd67b2fc11de75cc6c33c77e738fe59af97db895c5","old_source_span":[1196,1196],"old_content_sha256":"d16e602395b34a3cd4e40acd67b2fc11de75cc6c33c77e738fe59af97db895c5","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1197:1197:159ed03adadfbc7d231e91a8addcf73fb9ea56e0fd4bf31d0a028770f0763757","old_source_span":[1197,1197],"old_content_sha256":"159ed03adadfbc7d231e91a8addcf73fb9ea56e0fd4bf31d0a028770f0763757","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1210:1210:3d05d1e0d4afc37ecc7530fbadf0152ba9e42c33f809c0290c97d3db323875a7","old_source_span":[1210,1210],"old_content_sha256":"3d05d1e0d4afc37ecc7530fbadf0152ba9e42c33f809c0290c97d3db323875a7","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_mismatch_preserves_product_state","invariant_category":"grant_mutation_mismatch_preserves_product_state: Issue/revoke changed-reason conflicts keep product and reservation snapshots, adding exactly one typed bounded denial.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1211:1211:92e915d7c804d05e6ef48703ba42d342235f734db142d732166894c545286afe","old_source_span":[1211,1211],"old_content_sha256":"92e915d7c804d05e6ef48703ba42d342235f734db142d732166894c545286afe","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_mismatch_preserves_product_state","invariant_category":"grant_mutation_mismatch_preserves_product_state: Issue/revoke changed-reason conflicts keep product and reservation snapshots, adding exactly one typed bounded denial.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1212:1212:fa8e093248d515f44d032fdffb8e8e1a392a08637ee07099c6c955e06be5632b","old_source_span":[1212,1212],"old_content_sha256":"fa8e093248d515f44d032fdffb8e8e1a392a08637ee07099c6c955e06be5632b","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_distinct_operation_duplicate_grant_is_conflict","invariant_category":"distinct_operation_duplicate_grant_is_conflict","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1213:1213:3611dec3d5d8da6dc3e866a27e2731edf972dc23327ec3bc4387a572ad91719b","old_source_span":[1213,1213],"old_content_sha256":"3611dec3d5d8da6dc3e866a27e2731edf972dc23327ec3bc4387a572ad91719b","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_distinct_operation_duplicate_grant_is_conflict","invariant_category":"distinct_operation_duplicate_grant_is_conflict","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This distinct_operation_duplicate_grant_is_conflict assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1225:1225:a421b54f49968880b22cd22c2bc436c7e4216a6339cc10861a9236385ad07508","old_source_span":[1225,1225],"old_content_sha256":"a421b54f49968880b22cd22c2bc436c7e4216a6339cc10861a9236385ad07508","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_admin_grant_list_returns_exact_scope_and_count","invariant_category":"admin_grant_list_returns_exact_scope_and_count: Three real system grants retain total3; separate history test preserves the history half of combined200 assertion.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1226:1226:c262fa68a992d7583178397e651dec99449e6e52939ea7bd5010e3238481a0d8","old_source_span":[1226,1226],"old_content_sha256":"c262fa68a992d7583178397e651dec99449e6e52939ea7bd5010e3238481a0d8","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_admin_grant_list_returns_exact_scope_and_count","invariant_category":"admin_grant_list_returns_exact_scope_and_count: Three real system grants retain total3; separate history test preserves the history half of combined200 assertion.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_grant_list_returns_exact_scope_and_count assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1227:1227:6ef33fddbcd3f63f2e07b33fb307ad43364c8e67f6f1caceec89de218436c859","old_source_span":[1227,1227],"old_content_sha256":"6ef33fddbcd3f63f2e07b33fb307ad43364c8e67f6f1caceec89de218436c859","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_admin_grant_history_has_bounded_payload","invariant_category":"admin_grant_history_has_bounded_payload","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1228:1228:539ab6c8d1bf2f996c4884ce536c5731f9b9bebd46577d1ef0de56a828559f66","old_source_span":[1228,1228],"old_content_sha256":"539ab6c8d1bf2f996c4884ce536c5731f9b9bebd46577d1ef0de56a828559f66","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_admin_grant_history_has_bounded_payload","invariant_category":"admin_grant_history_has_bounded_payload","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1230:1230:1b65bdff12ea7df84fe9e2be9ff55a659f083868643a2ac4da6e36804e93db23","old_source_span":[1230,1230],"old_content_sha256":"1b65bdff12ea7df84fe9e2be9ff55a659f083868643a2ac4da6e36804e93db23","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_admin_grant_history_has_bounded_payload","invariant_category":"admin_grant_history_has_bounded_payload","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1231:1231:614092251f9eec07db957f33b2c8aa07dae1a2baec7982f428c51547c0049526","old_source_span":[1231,1231],"old_content_sha256":"614092251f9eec07db957f33b2c8aa07dae1a2baec7982f428c51547c0049526","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_admin_grant_history_has_bounded_payload","invariant_category":"admin_grant_history_has_bounded_payload","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_grant_history_has_bounded_payload assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1256:1256:f928b2314cf1c488971be11731800ddf39e701321bf36058c70e5f687338534b","old_source_span":[1256,1256],"old_content_sha256":"f928b2314cf1c488971be11731800ddf39e701321bf36058c70e5f687338534b","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1262:1262:e5864161bb871b953443e892a347ef392b8f03c9a44afdd684826dee24d8277a","old_source_span":[1262,1262],"old_content_sha256":"e5864161bb871b953443e892a347ef392b8f03c9a44afdd684826dee24d8277a","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1263:1263:f266e2ce426d56e33f052ee49791817880ae178fd9ffca8f58d2d181cdfd5b6b","old_source_span":[1263,1263],"old_content_sha256":"f266e2ce426d56e33f052ee49791817880ae178fd9ffca8f58d2d181cdfd5b6b","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1264:1264:82d52685c5c1acbf734e463aafcfc207304b22a1e08866498592cdb594d85059","old_source_span":[1264,1264],"old_content_sha256":"82d52685c5c1acbf734e463aafcfc207304b22a1e08866498592cdb594d85059","new_test_node":"tests/authorization/admin_access/test_grant_reads_postgresql.py::test_admin_grant_rejects_malformed_derivative_cursor","invariant_category":"admin_grant_rejects_malformed_derivative_cursor: Actual generated next cursor plus malformed suffix. Valid traversal separately covered by test_admin_grant_first_page_has_bounded_cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This admin_grant_rejects_malformed_derivative_cursor assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This admin_grant_rejects_malformed_derivative_cursor assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_grant_rejects_malformed_derivative_cursor assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This admin_grant_rejects_malformed_derivative_cursor assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This admin_grant_rejects_malformed_derivative_cursor assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This admin_grant_rejects_malformed_derivative_cursor assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This admin_grant_rejects_malformed_derivative_cursor assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1265:1265:dc39c1ca4da3746657e00ea1c697b2334abc6b6adae6c84bc99cbcf830a5045b","old_source_span":[1265,1265],"old_content_sha256":"dc39c1ca4da3746657e00ea1c697b2334abc6b6adae6c84bc99cbcf830a5045b","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1266:1266:c1a23c03ffa03ab716ceef503e6bd4c6b48af48c4c34052215e9826f33d0dd25","old_source_span":[1266,1266],"old_content_sha256":"c1a23c03ffa03ab716ceef503e6bd4c6b48af48c4c34052215e9826f33d0dd25","new_test_node":"tests/authorization/admin_access/test_grant_validation_postgresql.py::test_invalid_admin_request_is_bounded","invariant_category":"invalid_admin_request_is_bounded: Original cases: pending status; limits 0/101; malformed actor/grant UUID; unknown role/scope; operator project scope; oversized UTF-8 reason; absent project; system-with-project; project-without-project; invalid cursor.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This invalid_admin_request_is_bounded assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1273:1273:9a75ad57e22c9e02e54a12f13fdb9327b418a2500a91b62e0c4fc6b7e808d386","old_source_span":[1273,1273],"old_content_sha256":"9a75ad57e22c9e02e54a12f13fdb9327b418a2500a91b62e0c4fc6b7e808d386","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_target_role_projection_does_not_grant_catalogue_access","invariant_category":"target_role_projection_does_not_grant_catalogue_access: Role projection before/after operator revocation retains project-manager role; catalogue remains denied.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1274:1274:5bb6f2ff510b1f97c32fd7687955485c96fef252252b4084ee1aa36b98384295","old_source_span":[1274,1274],"old_content_sha256":"5bb6f2ff510b1f97c32fd7687955485c96fef252252b4084ee1aa36b98384295","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_target_role_projection_does_not_grant_catalogue_access","invariant_category":"target_role_projection_does_not_grant_catalogue_access: Role projection before/after operator revocation retains project-manager role; catalogue remains denied.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1275:1275:80027c2f0657e9ceeb6a0318c0dc6630ad760f85db646baffa55e1a517ef8204","old_source_span":[1275,1275],"old_content_sha256":"80027c2f0657e9ceeb6a0318c0dc6630ad760f85db646baffa55e1a517ef8204","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_target_role_projection_does_not_grant_catalogue_access","invariant_category":"target_role_projection_does_not_grant_catalogue_access: Role projection before/after operator revocation retains project-manager role; catalogue remains denied.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1287:1287:75c604e8d8feddc5899acaa303db59a22679c2fac504c99dfad34c2299a9ef0e","old_source_span":[1287,1287],"old_content_sha256":"75c604e8d8feddc5899acaa303db59a22679c2fac504c99dfad34c2299a9ef0e","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_grant_mutation_commit_failure_rolls_back","invariant_category":"grant_mutation_commit_failure_rolls_back: Issue and revoke independently stage actual product/evidence before fault, roll back, then retry the same key.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1288:1288:d49e8501131523a84424828a779b8b25f20ea0f15e11546874c0206e7722b230","old_source_span":[1288,1288],"old_content_sha256":"d49e8501131523a84424828a779b8b25f20ea0f15e11546874c0206e7722b230","new_test_node":"tests/authorization/admin_access/test_failure_atomicity_postgresql.py::test_grant_mutation_commit_failure_rolls_back","invariant_category":"grant_mutation_commit_failure_rolls_back: Issue and revoke independently stage actual product/evidence before fault, roll back, then retry the same key.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_commit_failure_rolls_back assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1295:1295:65423a34ba74daedda38877a3062193bf88fa34082b25a4261687d5f453f4293","old_source_span":[1295,1295],"old_content_sha256":"65423a34ba74daedda38877a3062193bf88fa34082b25a4261687d5f453f4293","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1296:1296:9a030d7ffb235188e07050366043b01f5c360195ce7bff469ea3014333e079e4","old_source_span":[1296,1296],"old_content_sha256":"9a030d7ffb235188e07050366043b01f5c360195ce7bff469ea3014333e079e4","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1302:1302:885024b96c0798d1985ba5d81028751a3316f2ae93cf213c07611fe24dc1a9de","old_source_span":[1302,1302],"old_content_sha256":"885024b96c0798d1985ba5d81028751a3316f2ae93cf213c07611fe24dc1a9de","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1303:1303:9bf46c32cb8cf0bd3b1268c5a57af7f36b6c324cc3a7b09793353c6199e39739","old_source_span":[1303,1303],"old_content_sha256":"9bf46c32cb8cf0bd3b1268c5a57af7f36b6c324cc3a7b09793353c6199e39739","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1304:1304:45c5aa3bd94f5daff849bbfc9bd467010cecf787a9b5680910779b88a0d6f8c9","old_source_span":[1304,1304],"old_content_sha256":"45c5aa3bd94f5daff849bbfc9bd467010cecf787a9b5680910779b88a0d6f8c9","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Issue and revoke independently preserve successful caller observation, stable response, exactly one operation and linked evidence.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1313:1313:a945735a6860867507e8cd8aa9faf6ad461f1a0616936b22e472caf2d3ff537f","old_source_span":[1313,1313],"old_content_sha256":"a945735a6860867507e8cd8aa9faf6ad461f1a0616936b22e472caf2d3ff537f","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_mismatch_preserves_product_state","invariant_category":"grant_mutation_mismatch_preserves_product_state: Issue/revoke changed-reason conflicts keep product and reservation snapshots, adding exactly one typed bounded denial.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1314:1314:755eb7198154622eef738505500513639a35140aa750947ea03025e75e474cc0","old_source_span":[1314,1314],"old_content_sha256":"755eb7198154622eef738505500513639a35140aa750947ea03025e75e474cc0","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_mismatch_preserves_product_state","invariant_category":"grant_mutation_mismatch_preserves_product_state: Issue/revoke changed-reason conflicts keep product and reservation snapshots, adding exactly one typed bounded denial.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1315:1315:11f5927e686247225ffbbdccbbb9b354776de0688ad7434e277c9aebd624fdfc","old_source_span":[1315,1315],"old_content_sha256":"11f5927e686247225ffbbdccbbb9b354776de0688ad7434e277c9aebd624fdfc","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_mismatch_preserves_product_state","invariant_category":"grant_mutation_mismatch_preserves_product_state: Issue/revoke changed-reason conflicts keep product and reservation snapshots, adding exactly one typed bounded denial.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1316:1316:df091ce1f0a57e40be7a5af325c5919a1a90fc4b9699c47d46d264947bd14498","old_source_span":[1316,1316],"old_content_sha256":"df091ce1f0a57e40be7a5af325c5919a1a90fc4b9699c47d46d264947bd14498","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_mismatch_preserves_product_state","invariant_category":"grant_mutation_mismatch_preserves_product_state: Issue/revoke changed-reason conflicts keep product and reservation snapshots, adding exactly one typed bounded denial.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_mismatch_preserves_product_state assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1333:1333:02903ac8e959b82b8ecd38369054e1e4d614437c1fedc07641e3c1d76171d892","old_source_span":[1333,1333],"old_content_sha256":"02903ac8e959b82b8ecd38369054e1e4d614437c1fedc07641e3c1d76171d892","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_revoked_and_absent_grants_share_concealed_revoke_response","invariant_category":"revoked_and_absent_grants_share_concealed_revoke_response","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1334:1334:0966390046e56d23fd319cab1b10644d3cb6e13ccb4b1f3cb935e67fb0942c84","old_source_span":[1334,1334],"old_content_sha256":"0966390046e56d23fd319cab1b10644d3cb6e13ccb4b1f3cb935e67fb0942c84","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_revoked_and_absent_grants_share_concealed_revoke_response","invariant_category":"revoked_and_absent_grants_share_concealed_revoke_response","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1340:1340:3a010e406fe91cf62f6b8d7b4530f941bebc098ab76650aa3a5058406de9dc31","old_source_span":[1340,1340],"old_content_sha256":"3a010e406fe91cf62f6b8d7b4530f941bebc098ab76650aa3a5058406de9dc31","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_revoked_and_absent_grants_share_concealed_revoke_response","invariant_category":"revoked_and_absent_grants_share_concealed_revoke_response","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":"preserved","revocation":"preserved","evidence":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This revoked_and_absent_grants_share_concealed_revoke_response assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":"preserved"}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1341:1341:e85698d3772e97e5e7c6bd929afb4d480d298b7ee7e1af2b16d0c32ea6ac2cc0","old_source_span":[1341,1341],"old_content_sha256":"e85698d3772e97e5e7c6bd929afb4d480d298b7ee7e1af2b16d0c32ea6ac2cc0","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_self_admin_revoke_preserves_grant","invariant_category":"self_admin_revoke_preserves_grant","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1342:1342:04dc8bfdc85f48093aadeda5a3873db660ee269663b0786aacb9f064209630a9","old_source_span":[1342,1342],"old_content_sha256":"04dc8bfdc85f48093aadeda5a3873db660ee269663b0786aacb9f064209630a9","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_self_admin_revoke_preserves_grant","invariant_category":"self_admin_revoke_preserves_grant","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This self_admin_revoke_preserves_grant assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1345:1345:f3ba4a9b52126688d3c8ca1e09f1a74a32b8f5637fe8391b0caad70127369e5c","old_source_span":[1345,1345],"old_content_sha256":"f3ba4a9b52126688d3c8ca1e09f1a74a32b8f5637fe8391b0caad70127369e5c","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_target_role_projection_does_not_grant_catalogue_access","invariant_category":"target_role_projection_does_not_grant_catalogue_access: Role projection before/after operator revocation retains project-manager role; catalogue remains denied.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":"preserved","replay":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no evidence claim; other independently mapped cases own that dimension."},"transaction_ownership":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no transaction ownership claim; other independently mapped cases own that dimension."},"concealment":{"not_applicable_reason":"This target_role_projection_does_not_grant_catalogue_access assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_signed_tokens_bootstrap_and_admin_grant_lifecycle","old_assertion_id":"assertion:1365:1370:d0aecbc5b7bfceb77171cd21983e4d3ced9c02548b14d09c1f8ef28b248c197d","old_source_span":[1365,1370],"old_content_sha256":"d0aecbc5b7bfceb77171cd21983e4d3ced9c02548b14d09c1f8ef28b248c197d","new_test_node":"tests/authorization/admin_access/test_grant_api_postgresql.py::test_grant_mutation_exact_replay_has_one_effect","invariant_category":"grant_mutation_exact_replay_has_one_effect: Aggregate1bootstrap/4issue/1revoke/5invalidation replaced by exact per-operation evidence: four original role/scope issue cases plus revoke, one success and linked invalidation each. Bootstrap single event survives test_later_bootstrap_returns_audited_original_grant_conflict. No shared-history total claimed.","target_layer":"integration","security_dimensions":{"concurrency":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concurrency claim; other independently mapped cases own that dimension."},"lock_order":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This grant_mutation_exact_replay_has_one_effect assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1552:1552:26bf4785aedf4b8e23ac577fb383e766b2f67b3a9745080f457896607f68f513","old_source_span":[1552,1552],"old_content_sha256":"26bf4785aedf4b8e23ac577fb383e766b2f67b3a9745080f457896607f68f513","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_concurrent_bootstrap_has_one_persisted_winner","invariant_category":"concurrent_bootstrap_has_one_persisted_winner","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":{"not_applicable_reason":"This concurrent_bootstrap_has_one_persisted_winner assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":{"not_applicable_reason":"This concurrent_bootstrap_has_one_persisted_winner assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This concurrent_bootstrap_has_one_persisted_winner assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1625:1625:2852c4fab102d7f3625da334b346bbe802d066ee5ca659a16ce44ad536b5777d","old_source_span":[1625,1625],"old_content_sha256":"2852c4fab102d7f3625da334b346bbe802d066ee5ca659a16ce44ad536b5777d","new_test_node":"tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py::test_older_read_cannot_regress_committed_observation","invariant_category":"older_read_cannot_regress_committed_observation: Actual delayed older request and captured newer commit, monotonic stored observations; no claim of row contention.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1626:1626:abbe87d5e79df46252ec2cf3ba8f7f3efb21505b4d9ae1a78044ca140bf5defc","old_source_span":[1626,1626],"old_content_sha256":"abbe87d5e79df46252ec2cf3ba8f7f3efb21505b4d9ae1a78044ca140bf5defc","new_test_node":"tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py::test_older_read_cannot_regress_committed_observation","invariant_category":"older_read_cannot_regress_committed_observation: Actual delayed older request and captured newer commit, monotonic stored observations; no claim of row contention.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1637:1637:154c5b499b3d7c1faf7d842cd858edf59fae96f78190b49d08594a6d6a528da0","old_source_span":[1637,1637],"old_content_sha256":"154c5b499b3d7c1faf7d842cd858edf59fae96f78190b49d08594a6d6a528da0","new_test_node":"tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py::test_older_read_cannot_regress_committed_observation","invariant_category":"older_read_cannot_regress_committed_observation: Actual delayed older request and captured newer commit, monotonic stored observations; no claim of row contention.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1638:1638:3ac99a80c5e224443cd89c8322098a93355cb0408652985f4d699b7238bc01e3","old_source_span":[1638,1638],"old_content_sha256":"3ac99a80c5e224443cd89c8322098a93355cb0408652985f4d699b7238bc01e3","new_test_node":"tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py::test_older_read_cannot_regress_committed_observation","invariant_category":"older_read_cannot_regress_committed_observation: Actual delayed older request and captured newer commit, monotonic stored observations; no claim of row contention.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1639:1639:a9b887a47be0ac314ed194286bbc12c9d6c764aa8cb2d0d11e8dc307a30ed865","old_source_span":[1639,1639],"old_content_sha256":"a9b887a47be0ac314ed194286bbc12c9d6c764aa8cb2d0d11e8dc307a30ed865","new_test_node":"tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py::test_older_read_cannot_regress_committed_observation","invariant_category":"older_read_cannot_regress_committed_observation: Actual delayed older request and captured newer commit, monotonic stored observations; no claim of row contention.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1640:1640:eb8cef051d3b096b9fd56e63b690028a708856484beeb774aac6fe5c0fa848e9","old_source_span":[1640,1640],"old_content_sha256":"eb8cef051d3b096b9fd56e63b690028a708856484beeb774aac6fe5c0fa848e9","new_test_node":"tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py::test_older_read_cannot_regress_committed_observation","invariant_category":"older_read_cannot_regress_committed_observation: Actual delayed older request and captured newer commit, monotonic stored observations; no claim of row contention.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1641:1641:2b2fab16b737049868c41055e35059dc60beb9997ac3b027ac05f642f0d688d1","old_source_span":[1641,1641],"old_content_sha256":"2b2fab16b737049868c41055e35059dc60beb9997ac3b027ac05f642f0d688d1","new_test_node":"tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py::test_older_read_cannot_regress_committed_observation","invariant_category":"older_read_cannot_regress_committed_observation: Actual delayed older request and captured newer commit, monotonic stored observations; no claim of row contention.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no lock order claim; other independently mapped cases own that dimension."},"denial_side_effects":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This older_read_cannot_regress_committed_observation assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1675:1675:bfeffe6ef291c39862248771e641036f08bbe1e469715f99fe59d6d44373be8c","old_source_span":[1675,1675],"old_content_sha256":"bfeffe6ef291c39862248771e641036f08bbe1e469715f99fe59d6d44373be8c","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_concurrent_same_key_grant_returns_one_result","invariant_category":"concurrent_same_key_grant_returns_one_result","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":{"not_applicable_reason":"This concurrent_same_key_grant_returns_one_result assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":{"not_applicable_reason":"This concurrent_same_key_grant_returns_one_result assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This concurrent_same_key_grant_returns_one_result assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1676:1676:941dd0ca73e10126fddd7c5c7f29d1c0b39d0c7f2f4fa35c13ffd104b1b07874","old_source_span":[1676,1676],"old_content_sha256":"941dd0ca73e10126fddd7c5c7f29d1c0b39d0c7f2f4fa35c13ffd104b1b07874","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_concurrent_same_key_grant_returns_one_result","invariant_category":"concurrent_same_key_grant_returns_one_result","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":{"not_applicable_reason":"This concurrent_same_key_grant_returns_one_result assertion makes no denial side effects claim; other independently mapped cases own that dimension."},"replay":"preserved","revocation":{"not_applicable_reason":"This concurrent_same_key_grant_returns_one_result assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This concurrent_same_key_grant_returns_one_result assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1713:1713:c6104dd40a479306c605cc7df0cbb0e3367d384c05205e98649101ee64e76849","old_source_span":[1713,1713],"old_content_sha256":"c6104dd40a479306c605cc7df0cbb0e3367d384c05205e98649101ee64e76849","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_concurrent_distinct_keys_create_one_active_grant","invariant_category":"concurrent_distinct_keys_create_one_active_grant","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This concurrent_distinct_keys_create_one_active_grant assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This concurrent_distinct_keys_create_one_active_grant assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1714:1719:b8cb8915f313024fba02186f0cadab1e15ff5350e7129992b15989c8cc9394ab","old_source_span":[1714,1719],"old_content_sha256":"b8cb8915f313024fba02186f0cadab1e15ff5350e7129992b15989c8cc9394ab","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_concurrent_distinct_keys_create_one_active_grant","invariant_category":"concurrent_distinct_keys_create_one_active_grant","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":"preserved","revocation":{"not_applicable_reason":"This concurrent_distinct_keys_create_one_active_grant assertion makes no revocation claim; other independently mapped cases own that dimension."},"evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This concurrent_distinct_keys_create_one_active_grant assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1732:1732:e609834893123f120a156dca27feb569cb76bc79c6f4409c1c8a5ce31bf1efd6","old_source_span":[1732,1732],"old_content_sha256":"e609834893123f120a156dca27feb569cb76bc79c6f4409c1c8a5ce31bf1efd6","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1768:1768:adea16d475647a5ddf6c5bc49b9f4021cb7c8130274048e372275ba04f33d563","old_source_span":[1768,1768],"old_content_sha256":"adea16d475647a5ddf6c5bc49b9f4021cb7c8130274048e372275ba04f33d563","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1769:1774:1cd08560946f2aa00d333e076cd6a555c172f7776f3f49cdb401ca55b592720a","old_source_span":[1769,1774],"old_content_sha256":"1cd08560946f2aa00d333e076cd6a555c172f7776f3f49cdb401ca55b592720a","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1796:1796:4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","old_source_span":[1796,1796],"old_content_sha256":"4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1865:1865:17d2fa2835e23a18f95b838daac7dc68bec4cc625aa11545c044d65d67810a1f","old_source_span":[1865,1865],"old_content_sha256":"17d2fa2835e23a18f95b838daac7dc68bec4cc625aa11545c044d65d67810a1f","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1866:1866:6bbecb8449be355265b77461b498f0118aa20bb450bf1ca91c60d3a053d43b70","old_source_span":[1866,1866],"old_content_sha256":"6bbecb8449be355265b77461b498f0118aa20bb450bf1ca91c60d3a053d43b70","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1877:1877:0a8d3fcd723db576987edc2d0974d17024f4093bc42a387cd84755f1dd53715a","old_source_span":[1877,1877],"old_content_sha256":"0a8d3fcd723db576987edc2d0974d17024f4093bc42a387cd84755f1dd53715a","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1878:1878:5f46e023d3a84db670f65960ee5d02a313ab1e37c0b71e53b99e7a49d16be543","old_source_span":[1878,1878],"old_content_sha256":"5f46e023d3a84db670f65960ee5d02a313ab1e37c0b71e53b99e7a49d16be543","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1879:1879:a52256849581efd03fac92e1a9e767598a3ad0f8b22fc37e18eccd2d13778f22","old_source_span":[1879,1879],"old_content_sha256":"a52256849581efd03fac92e1a9e767598a3ad0f8b22fc37e18eccd2d13778f22","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1931:1931:e6c63b223a08a1ff685b1f394ba288ad5f6e381125f0506fc0f18e41ece4f35d","old_source_span":[1931,1931],"old_content_sha256":"e6c63b223a08a1ff685b1f394ba288ad5f6e381125f0506fc0f18e41ece4f35d","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1961:1961:8b20d628974b6e826a17657405fdb73ac5621091d58580ee13a564af7d0bd42f","old_source_span":[1961,1961],"old_content_sha256":"8b20d628974b6e826a17657405fdb73ac5621091d58580ee13a564af7d0bd42f","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1962:1967:aac9ecf6e18c4e4e2a6a0fbed938adf99427128bc0061cf83ef42ee7d11ddb2b","old_source_span":[1962,1967],"old_content_sha256":"aac9ecf6e18c4e4e2a6a0fbed938adf99427128bc0061cf83ef42ee7d11ddb2b","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Shared-history event totals decomposed: bootstrap success/conflict in test_concurrent_bootstrap_has_one_persisted_winner; same-key issue in test_concurrent_same_key_grant_returns_one_result; duplicate issue/denial in test_concurrent_distinct_keys_create_one_active_grant; cross-revoke in test_cross_revoke_retains_one_effective_admin; both issue/revoke orders here. Exact per-effect counts replace incidental fixture aggregate.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1968:1968:4c6e959ec302fee13a375e96b4aebefa6bbece07c3b340c58d97a07f11f3ae23","old_source_span":[1968,1968],"old_content_sha256":"4c6e959ec302fee13a375e96b4aebefa6bbece07c3b340c58d97a07f11f3ae23","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1969:1969:b281467fa2851b3de536939c3095a4a0180a938bca655f15b1a2a3fb2757d4f3","old_source_span":[1969,1969],"old_content_sha256":"b281467fa2851b3de536939c3095a4a0180a938bca655f15b1a2a3fb2757d4f3","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1970:1970:dcb078e3f7f67ed92f063ecfca34e4166f43733dcc925c10fbb338dbbeeec1fe","old_source_span":[1970,1970],"old_content_sha256":"dcb078e3f7f67ed92f063ecfca34e4166f43733dcc925c10fbb338dbbeeec1fe","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2159:2159:d87c0219fc92b124096bf360534a2e340f2d761ddbf207bce50acf9de469052d","old_source_span":[2159,2159],"old_content_sha256":"d87c0219fc92b124096bf360534a2e340f2d761ddbf207bce50acf9de469052d","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2173:2173:6dce1bc0c02aadfd584523b98af65c756763668bd573298ce01178609156840d","old_source_span":[2173,2173],"old_content_sha256":"6dce1bc0c02aadfd584523b98af65c756763668bd573298ce01178609156840d","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2220:2220:a814b4c43bf407658a1bdc7f6b5c1803ccdb296b30f969d0d66ba5f1b3eb2888","old_source_span":[2220,2220],"old_content_sha256":"a814b4c43bf407658a1bdc7f6b5c1803ccdb296b30f969d0d66ba5f1b3eb2888","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2222:2222:0bfb1014673a039e2f98e4f384eda0b427d40cb61c88a8b19abb198e7c4a1352","old_source_span":[2222,2222],"old_content_sha256":"0bfb1014673a039e2f98e4f384eda0b427d40cb61c88a8b19abb198e7c4a1352","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2228:2228:81dc6f8856d4b1ece0307b7a02898dc185f66c509d34ef182d247aebb5b67c36","old_source_span":[2228,2228],"old_content_sha256":"81dc6f8856d4b1ece0307b7a02898dc185f66c509d34ef182d247aebb5b67c36","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2229:2229:37f7c88b94a30c91e68f4665be3fe1dee3e1c19290784f3c9ea6c48fb306dff4","old_source_span":[2229,2229],"old_content_sha256":"37f7c88b94a30c91e68f4665be3fe1dee3e1c19290784f3c9ea6c48fb306dff4","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2251:2251:df73f76b66ae448b1b41cc469779354679b15d21310fd1512becb6a0c448bc09","old_source_span":[2251,2251],"old_content_sha256":"df73f76b66ae448b1b41cc469779354679b15d21310fd1512becb6a0c448bc09","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}} ] } diff --git a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md index 1084a48cf..0278fe127 100644 --- a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md +++ b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md @@ -56,6 +56,10 @@ These are observed proof weaknesses, not established production defects. - New `backend/tests/authorization/admin_access/` package with `__init__.py`, `conftest.py`, `support.py`, `fixtures.py`, `fault_support.py`, `concurrency_support.py`, `read_support.py` and the test files below. + `test_grant_reads_postgresql.py` and `test_grant_validation_postgresql.py` + separate grant query/scoping and request validation from actor disclosure and + mutation recovery. This implementation scope refinement keeps each owner file + below 500 lines without removing any selected behavior or adding runtime scope. Split support further only by a named behavior and record the scope correction before implementation; no arbitrary helper framework. - `.ci/auth-boundaries/TEST_STRUCTURE_DEBT.json` and new assertion map @@ -259,5 +263,26 @@ explicit sibling exports. The new owner directory is explicitly scanned and registered in existing lanes. All eighteen tests still in the monolith retain AST-identical bodies at this checkpoint. Mixed fixture collection succeeds; that is not PostgreSQL execution. The three selected large API/concurrency -functions and their 188 original assertion spans still require the subsequent +functions and their 188 original assertion spans were reserved for the subsequent implementation checkpoint and hosted proof in this same PR. + +The second checkpoint supplies that API/PostgreSQL split and maps all 203 +original assertion spans before removing the eight selected source functions. +The fifteen unselected test bodies remain AST-identical. The signed journey is +retained; grant query and request validation get separate named files to keep +actor disclosure, grant recovery, and malformed-input proof independently readable. +No production code is changed. + +Actual transaction snapshots replace rollback counts: failure probes flush and +read staged product/evidence in the owning session before raising, then tests +compare fresh-session state. Concurrency harnesses retain real owner calls and +observe exact independent waiter/blocker PIDs. Read transitions use fresh rows +with triggers enabled, eliminating lifecycle reset bypasses. Test names describe +these required observations, not a claim that hosted execution has already passed. + +The old aggregate event counts are decomposed into exact operation-scoped success, +denial and linked invalidation assertions; the map names the sibling survivors. +CLI privacy and empty-stderr proof remain unchanged from the first checkpoint. +All new PostgreSQL modules are explicitly registered in existing hosted lanes. +This checkpoint still requires hosted PostgreSQL results, fault/lock probes, +and affected exact-head reviews before the PR can be reported ready. diff --git a/backend/scripts/test_lane_catalogue.py b/backend/scripts/test_lane_catalogue.py index ef2094dab..5f5446646 100644 --- a/backend/scripts/test_lane_catalogue.py +++ b/backend/scripts/test_lane_catalogue.py @@ -123,6 +123,16 @@ class TestLane: "tests/test_audit.py", "tests/test_auth.py", "tests/authorization/admin_access/test_bootstrap_cli.py", + "tests/authorization/admin_access/test_api_journey.py", + "tests/authorization/admin_access/test_bootstrap_postgresql.py", + "tests/authorization/admin_access/test_admin_reads_postgresql.py", + "tests/authorization/admin_access/test_grant_api_postgresql.py", + "tests/authorization/admin_access/test_grant_reads_postgresql.py", + "tests/authorization/admin_access/test_grant_validation_postgresql.py", + "tests/authorization/admin_access/test_failure_atomicity_postgresql.py", + "tests/authorization/admin_access/test_grant_concurrency_postgresql.py", + "tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py", + "tests/authorization/admin_access/test_read_concurrency_postgresql.py", "tests/test_auth_concurrency_observer.py", "tests/test_authorization.py", "tests/authorization/guide_compilation/test_adapter_contract.py", diff --git a/backend/tests/authorization/admin_access/concurrency_support.py b/backend/tests/authorization/admin_access/concurrency_support.py new file mode 100644 index 000000000..7a4ddcab5 --- /dev/null +++ b/backend/tests/authorization/admin_access/concurrency_support.py @@ -0,0 +1,227 @@ +"""Hold the actual owner lock until an independent observer sees the exact waiter.""" + +import asyncio +from collections.abc import Awaitable, Callable +from dataclasses import dataclass +from typing import Any +from uuid import uuid4 + +import pytest +from sqlalchemy import text + +from app.db import session as db_session +from app.modules.actors.service import ActorService + +from app.modules.authorization.repository import ( + AdminAuthorizationRepository, + AuthorityIdempotencyRepository, +) +from tests.auth_concurrency_support import wait_for_named_database_lock +from tests.authorization.admin_access.read_support import read_path +from tests.authorization.admin_access.support import AdminAccess, SignedActor + + +@dataclass +class LockObservation: + holder_pid: int | None = None + waiter_pid: int | None = None + observed: bool = False + + +async def ordered_owner_calls( + first: Callable[[], Awaitable[Any]], + second: Callable[[], Awaitable[Any]], + *, + boundary: str, + database_url: str, + monkeypatch: pytest.MonkeyPatch, +) -> tuple[Any, Any, LockObservation]: + """Run two named operations and propagate hook failures outside HTTP concealment.""" + assert boundary in {"control", "reservation"} + owner, method = ( + (AdminAuthorizationRepository, "lock_control") + if boundary == "control" + else (AuthorityIdempotencyRepository, "reserve") + ) + original = getattr(owner, method) + held, waiter_ready = asyncio.Event(), asyncio.Event() + identity = f"admin-race-{uuid4().hex}" + observation = LockObservation() + entered: set[str] = set() + failures: list[Exception] = [] + tasks: list[asyncio.Task] = [] + + async def hook(repository, *args, **kwargs): + task = asyncio.current_task() + assert task is not None + name = task.get_name() + if name not in {identity + "-holder", identity + "-waiter"} or name in entered: + return await original(repository, *args, **kwargs) + entered.add(name) + try: + if name.endswith("-holder"): + observation.holder_pid = await repository._session.scalar( + text("select pg_backend_pid()") + ) + result = await original(repository, *args, **kwargs) + held.set() + await waiter_ready.wait() + assert observation.holder_pid != observation.waiter_pid + await wait_for_named_database_lock( + database_url, + identity, + expected_waiter_pid=observation.waiter_pid, + expected_blocker_pid=observation.holder_pid, + ) + observation.observed = True + return result + await held.wait() + await repository._session.execute( + text("select set_config('application_name', :name, true)"), + {"name": identity}, + ) + observation.waiter_pid = await repository._session.scalar( + text("select pg_backend_pid()") + ) + waiter_ready.set() + return await original(repository, *args, **kwargs) + except Exception as exc: + failures.append(exc) + raise + + with monkeypatch.context() as patch: + patch.setattr(owner, method, hook) + try: + tasks = [ + asyncio.create_task(first(), name=identity + "-holder"), + asyncio.create_task(second(), name=identity + "-waiter"), + ] + results = await asyncio.wait_for(asyncio.gather(*tasks), timeout=60) + finally: + for task in tasks: + if not task.done(): + task.cancel() + await asyncio.gather(*tasks, return_exceptions=True) + if failures: + raise AssertionError("actual owner lock observation failed") from failures[0] + assert observation.observed, "both operations must reach the intended lock" + assert observation.holder_pid is not None and observation.waiter_pid is not None + return results[0], results[1], observation + + +async def apply_disabling_transition( + access: AdminAccess, + reader: SignedActor, + grant_id: str, + transition: str, + capture: Callable[..., Awaitable[None]], +): + """Grant uses HTTP; profile/link SQL proves row custody with triggers enabled.""" + if transition == "grant_revoked": + return await access.signed.revoke(access.admin, grant_id) + statements = { + "suspended": "update actor_profiles set status='suspended',suspended_by=:by," + "suspended_at=clock_timestamp(),suspension_reason='race proof' where id=:actor", + "deactivated": "update actor_profiles set status='deactivated',deactivated_by=:by," + "deactivated_at=clock_timestamp(),deactivation_reason='race proof' where id=:actor", + "link_revoked": "update actor_identity_links set status='revoked',revoked_by=:by," + "revoked_at=clock_timestamp(),revoked_reason='race proof' where actor_profile_id=:actor", + } + async with db_session.get_session_factory()() as session: + await capture(session) + await session.execute( + text(statements[transition]), + { + "actor": str(reader.id), + "by": str(access.admin.id), + }, + ) + await session.commit() + + +async def read_against_transition( + access: AdminAccess, + reader: SignedActor, + grant_id: str, + surface: str, + transition: str, + *, + database_url: str, + monkeypatch: pytest.MonkeyPatch, +) -> tuple[Any, Any, LockObservation]: + """Release disclosure only after its exact transaction blocks the transition.""" + identity = f"read-race-{uuid4().hex}" + entered, release, waiter_ready = asyncio.Event(), asyncio.Event(), asyncio.Event() + observation = LockObservation() + tasks: list[asyncio.Task] = [] + failures: list[Exception] = [] + method = "read_admin_profile" if surface == "profile" else "read_admin_identity_link" + original_read = getattr(ActorService, method) + original_get_grant = AdminAuthorizationRepository.get_grant + + async def capture(session): + if observation.waiter_pid is None: + await session.execute( + text("select set_config('application_name', :name, true)"), {"name": identity} + ) + observation.waiter_pid = await session.scalar(text("select pg_backend_pid()")) + waiter_ready.set() + + async def paused_read(service, target): + observation.holder_pid = await service._session.scalar(text("select pg_backend_pid()")) + entered.set() + await release.wait() + return await original_read(service, target) + + async def captured_grant(repository, *args, **kwargs): + task = asyncio.current_task() + if task is not None and task.get_name() == identity + "-transition": + try: + await capture(repository._session) + except Exception as exc: + failures.append(exc) + raise + return await original_get_grant(repository, *args, **kwargs) + + async def transition_after_read(): + await entered.wait() + return await apply_disabling_transition(access, reader, grant_id, transition, capture) + + async def observe_then_release(): + await waiter_ready.wait() + assert observation.holder_pid is not None and observation.waiter_pid is not None + assert observation.holder_pid != observation.waiter_pid + await wait_for_named_database_lock( + database_url, + identity, + expected_waiter_pid=observation.waiter_pid, + expected_blocker_pid=observation.holder_pid, + ) + observation.observed = True + release.set() + + with monkeypatch.context() as patch: + patch.setattr(ActorService, method, paused_read) + patch.setattr(AdminAuthorizationRepository, "get_grant", captured_grant) + try: + tasks = [ + asyncio.create_task( + access.signed.client.get( + read_path(access.target.id, surface), + headers=reader.headers, + ), + name=identity + "-reader", + ), + asyncio.create_task(transition_after_read(), name=identity + "-transition"), + asyncio.create_task(observe_then_release(), name=identity + "-observer"), + ] + results = await asyncio.wait_for(asyncio.gather(*tasks), timeout=60) + finally: + for task in tasks: + if not task.done(): + task.cancel() + await asyncio.gather(*tasks, return_exceptions=True) + if failures: + raise AssertionError("transition session capture failed") from failures[0] + assert observation.observed + return results[0], results[1], observation diff --git a/backend/tests/authorization/admin_access/conftest.py b/backend/tests/authorization/admin_access/conftest.py index be8f38d81..d416d38db 100644 --- a/backend/tests/authorization/admin_access/conftest.py +++ b/backend/tests/authorization/admin_access/conftest.py @@ -5,3 +5,7 @@ clear_settings_cache as clear_settings_cache, rsa_signing_material as rsa_signing_material, ) +from tests.authorization.admin_access.fixtures import ( + signed_access as signed_access, + admin_access as admin_access, +) diff --git a/backend/tests/authorization/admin_access/fault_support.py b/backend/tests/authorization/admin_access/fault_support.py new file mode 100644 index 000000000..e8c5deb63 --- /dev/null +++ b/backend/tests/authorization/admin_access/fault_support.py @@ -0,0 +1,87 @@ +"""One-shot failures capture real transaction state before raising a database error.""" + +from dataclasses import dataclass +from typing import Any +from uuid import UUID + +import pytest +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.ext.asyncio import AsyncSession + +from app.modules.actors.service import ActorService +from app.modules.audit.service import AuditService +from tests.authorization.admin_access.read_support import READ_ACTIONS +from tests.authorization.admin_access.support import ( + ActorObservation, + observed_actor, + stored_authority, +) + + +@dataclass +class FailureObservation: + actor_id: UUID + rows: dict[str, list[dict[str, Any]]] | None = None + actor: ActorObservation | None = None + + async def capture(self, session: AsyncSession) -> None: + await session.flush() + self.rows = await stored_authority(session) + self.actor = await observed_actor(session, self.actor_id) + + +def fail_next_commit(monkeypatch: pytest.MonkeyPatch, actor_id: UUID) -> FailureObservation: + """Do not synthesize writes; inspect the actual first commit's transaction.""" + probe = FailureObservation(actor_id) + original = AsyncSession.commit + attempted = False + + async def fail_commit(session): + nonlocal attempted + if attempted: + return await original(session) + attempted = True + await probe.capture(session) + raise SQLAlchemyError("injected late commit failure") + + monkeypatch.setattr(AsyncSession, "commit", fail_commit) + return probe + + +def fail_admin_read( + monkeypatch: pytest.MonkeyPatch, + actor_id: UUID, + surface: str, + stage: str, +) -> FailureObservation: + if stage == "commit": + return fail_next_commit(monkeypatch, actor_id) + probe = FailureObservation(actor_id) + if stage == "evidence": + original = AuditService.add_authority_event + action, _ = READ_ACTIONS[surface] + + async def fail_evidence(service, value): + if value.action_id is not None and value.action_id.value == action: + await probe.capture(service._repository._session) + raise SQLAlchemyError("injected pre-evidence failure") + return await original(service, value) + + monkeypatch.setattr(AuditService, "add_authority_event", fail_evidence) + elif stage == "lookup": + method = "read_admin_profile" if surface == "profile" else "read_admin_identity_link" + + async def fail_lookup(service, _target): + await probe.capture(service._session) + raise SQLAlchemyError("injected target lookup failure") + + monkeypatch.setattr(ActorService, method, fail_lookup) + else: + assert stage == "touch" + + async def fail_touch(service, _resolved): + await probe.capture(service._session) + raise SQLAlchemyError("injected pre-touch failure") + + monkeypatch.setattr(ActorService, "touch_after_authorization", fail_touch) + return probe diff --git a/backend/tests/authorization/admin_access/fixtures.py b/backend/tests/authorization/admin_access/fixtures.py new file mode 100644 index 000000000..ff3c3484f --- /dev/null +++ b/backend/tests/authorization/admin_access/fixtures.py @@ -0,0 +1,43 @@ +"""Valid signed API setup; tests own each mutation and its assertions.""" + +from collections.abc import AsyncIterator + +from httpx import ASGITransport, AsyncClient +import pytest + +from app.adapters.auth.flow import FlowAuthVerifier +from app.db import session as db_session +from app.main import create_app +from scripts.bootstrap_access_administrator import _run as run_bootstrap +from tests.authentication.support import production_verifier_settings, jwks_transport +from tests.authorization.admin_access.support import AdminAccess, SignedAccess + + +@pytest.fixture +async def signed_access(auth_database_env, rsa_signing_material) -> AsyncIterator[SignedAccess]: + private_key, jwk = rsa_signing_material + settings = production_verifier_settings(database_url=auth_database_env) + app = create_app(settings) + app.state.auth_verifier = FlowAuthVerifier(settings, jwks_transport=jwks_transport(jwk)) + try: + async with AsyncClient( + transport=ASGITransport(app=app), base_url="http://testserver" + ) as client: + yield SignedAccess(client, private_key) + finally: + await db_session.dispose_engine() + + +@pytest.fixture +async def admin_access(signed_access: SignedAccess) -> AdminAccess: + admin = await signed_access.actor("administrator", roles=("viewer",)) + target = await signed_access.actor("target", roles=("admin",)) + code, result = await run_bootstrap(admin.id, execute=True) + assert code == 0, result + assert result == { + "result_code": "bootstrapped", + "actor_profile_id": str(admin.id), + "grant_id": result["grant_id"], + "changed": True, + } + return AdminAccess(signed_access, admin, target, result["grant_id"]) diff --git a/backend/tests/authorization/admin_access/read_support.py b/backend/tests/authorization/admin_access/read_support.py new file mode 100644 index 000000000..9f07f194f --- /dev/null +++ b/backend/tests/authorization/admin_access/read_support.py @@ -0,0 +1,124 @@ +"""Fresh stored targets and explicit public projections for administrative reads.""" + +from dataclasses import dataclass +from datetime import UTC, datetime +from uuid import UUID, uuid4 + +from app.db import session as db_session +from app.modules.actors.models import ActorIdentityLink, ActorProfile +from app.modules.actors.api import ServiceIdentity +from tests.authorization.admin_access.support import AdminAccess + +PROFILE_FIELDS = { + "actor_profile_id", + "actor_kind", + "status", + "provisioning_method", + "service_identity", + "display_name", + "created_at", + "updated_at", + "last_seen_at", + "suspended_at", + "reactivated_at", + "deactivated_at", +} +LINK_FIELDS = { + "identity_link_id", + "actor_profile_id", + "subject_kind", + "status", + "linked_at", + "last_verified_at", + "revoked_at", + "reactivated_at", +} +READ_ACTIONS = { + "profile": ("actor.profile.read", "actor.profile.read_any"), + "link": ("actor.identity_link.read", "actor.identity_link.read"), +} + + +def read_path(actor_id: UUID, surface: str) -> str: + assert surface in READ_ACTIONS + return f"/api/v1/actors/{actor_id}" + ("/identity-links" if surface == "link" else "") + + +@dataclass(frozen=True) +class ReadTarget: + id: UUID + private_values: tuple[str, ...] + + +async def seed_read_target(access: AdminAccess, kind: str) -> ReadTarget: + """Create valid fresh rows; no lifecycle trigger is disabled or state reset.""" + assert kind in {"human", "service", "suspended", "revoked_link"} + email = "private-contact@example.test" + if kind == "human": + async with db_session.get_session_factory()() as session: + profile = await session.get(ActorProfile, str(access.target.id)) + assert profile is not None + profile.contact_email = email + await session.commit() + return ReadTarget( + access.target.id, + ( + email, + access.target.subject, + access.target.token, + access.admin.token, + access.bootstrap_grant_id, + "https://identity.test", + ), + ) + actor_id = uuid4() + subject = f"private-{kind}-{uuid4()}" + provenance = str(uuid4()) + reason = "Private lifecycle reason" + now = datetime.now(UTC) + actor_kind = "service" if kind == "service" else "human" + profile = ActorProfile( + id=str(actor_id), + actor_kind=actor_kind, + status="suspended" if kind == "suspended" else "active", + provisioning_method=( + "manual_service_provisioning" if kind == "service" else "automatic_first_access" + ), + service_identity=ServiceIdentity.ARTIFACT_VERIFIER.value if kind == "service" else None, + created_by=provenance, + ) + if kind == "suspended": + profile.suspended_by = provenance + profile.suspended_at = now + profile.suspension_reason = reason + link = ActorIdentityLink( + id=str(uuid4()), + actor_profile_id=str(actor_id), + issuer="https://identity.test", + subject=subject, + subject_kind=actor_kind, + status="revoked" if kind == "revoked_link" else "active", + linked_by=provenance, + last_verified_at=None if kind == "service" else now, + ) + if kind == "revoked_link": + link.revoked_by = provenance + link.revoked_at = now + link.revoked_reason = reason + async with db_session.get_session_factory()() as session: + session.add(profile) + await session.flush() + session.add(link) + await session.commit() + return ReadTarget( + actor_id, + ( + subject, + provenance, + reason, + "https://identity.test", + access.admin.token, + access.target.token, + access.bootstrap_grant_id, + ), + ) diff --git a/backend/tests/authorization/admin_access/support.py b/backend/tests/authorization/admin_access/support.py new file mode 100644 index 000000000..388f23a9c --- /dev/null +++ b/backend/tests/authorization/admin_access/support.py @@ -0,0 +1,204 @@ +"""Real signed requests and narrow PostgreSQL observations for admin tests.""" + +from dataclasses import dataclass +from datetime import UTC, datetime +from typing import Any +from uuid import UUID, uuid4 + +from cryptography.hazmat.primitives.asymmetric import rsa +from httpx import AsyncClient, Response +from sqlalchemy import select, text +from sqlalchemy.ext.asyncio import AsyncSession + +from app.db import session as db_session +from app.modules.authorization.models import ( + AdminRoleGrant, + AuthorityControl, + AuthorityIdempotencyRecord, +) +from app.modules.tasks.models import AuditEvent +from project_create_fixtures import seed_historical_project +from tests.authentication.support import issue_asymmetric_token + + +@dataclass(frozen=True) +class SignedActor: + id: UUID + subject: str + token: str + + @property + def headers(self) -> dict[str, str]: + return {"Authorization": f"Bearer {self.token}"} + + +@dataclass +class SignedAccess: + client: AsyncClient + private_key: rsa.RSAPrivateKey + + async def actor(self, label: str, *, roles: tuple[str, ...] = ()) -> SignedActor: + subject = f"{label}-{uuid4()}" + token = issue_asymmetric_token( + self.private_key, + claims={"sub": subject, "jti": str(uuid4()), "roles": list(roles)}, + ) + response = await self.client.get( + "/api/v1/actors/me", headers={"Authorization": f"Bearer {token}"} + ) + assert response.status_code == 200, response.text + return SignedActor(UUID(response.json()["actor_profile_id"]), subject, token) + + async def issue( + self, caller: SignedActor, body: dict[str, Any], *, key: str | None = None + ) -> Response: + return await self.client.post( + "/api/v1/admin-role-grants", + headers=caller.headers | {"Idempotency-Key": key or str(uuid4())}, + json=body, + ) + + async def revoke( + self, + caller: SignedActor, + grant_id: str, + *, + key: str | None = None, + reason: str = "End assigned authority", + ) -> Response: + return await self.client.post( + f"/api/v1/admin-role-grants/{grant_id}/revoke", + headers=caller.headers | {"Idempotency-Key": key or str(uuid4())}, + json={"reason": reason}, + ) + + async def grant( + self, + caller: SignedActor, + target: SignedActor, + *, + role: str = "operator", + project_id: UUID | None = None, + ) -> str: + response = await self.issue(caller, grant_body(target.id, role=role, project_id=project_id)) + assert response.status_code == 201, response.text + return response.json()["resource_id"] + + +@dataclass(frozen=True) +class AdminAccess: + signed: SignedAccess + admin: SignedActor + target: SignedActor + bootstrap_grant_id: str + + +def grant_body( + actor_id: UUID, *, role: str = "operator", project_id: UUID | None = None +) -> dict[str, Any]: + return { + "target_actor_profile_id": str(actor_id), + "role": role, + "scope_type": "system" if project_id is None else "project", + "scope_project_id": None if project_id is None else str(project_id), + "reason": "Explicit administrator assignment", + } + + +async def create_project(label: str) -> UUID: + project_id = uuid4() + async with db_session.get_session_factory()() as session: + await seed_historical_project( + session, project_id=str(project_id), name=label, slug=f"admin-{project_id}" + ) + await session.commit() + return project_id + + +@dataclass(frozen=True) +class ActorObservation: + display_name: str | None + updated_at: datetime + last_seen_at: datetime + last_verified_at: datetime + + +async def actor_observation(actor_id: UUID) -> ActorObservation: + async with db_session.get_session_factory()() as session: + return await observed_actor(session, actor_id) + + +async def observed_actor(session: AsyncSession, actor_id: UUID) -> ActorObservation: + """Read this session's visible observations for an already admitted human.""" + row = ( + await session.execute( + text( + "select p.display_name,p.updated_at,p.last_seen_at,l.last_verified_at " + "from actor_profiles p join actor_identity_links l " + "on l.actor_profile_id=p.id where p.id=:actor" + ), + {"actor": str(actor_id)}, + ) + ).one() + assert all(isinstance(value, datetime) for value in row[1:]) + return ActorObservation(*row) + + +async def seed_old_observation(actor_id: UUID) -> ActorObservation: + async with db_session.get_session_factory()() as session: + parameters = {"actor": str(actor_id), "old": datetime(2000, 1, 1, tzinfo=UTC)} + await session.execute( + text("update actor_profiles set last_seen_at=:old,updated_at=:old where id=:actor"), + parameters, + ) + await session.execute( + text( + "update actor_identity_links set last_verified_at=:old " + "where actor_profile_id=:actor" + ), + parameters, + ) + await session.commit() + return await actor_observation(actor_id) + + +async def authority_snapshot() -> dict[str, list[dict[str, Any]]]: + """Snapshot actual stored values, not counts that could miss a rolled-back revoke.""" + async with db_session.get_session_factory()() as session: + return await stored_authority(session) + + +async def stored_authority(session: AsyncSession) -> dict[str, list[dict[str, Any]]]: + """Use the supplied transaction so late-failure proof sees actual staged rows.""" + result = {} + for model in (AdminRoleGrant, AuthorityControl, AuthorityIdempotencyRecord, AuditEvent): + rows = await session.execute(select(model.__table__).order_by(model.id)) + result[model.__tablename__] = [dict(row) for row in rows.mappings()] + return result + + +async def authority_events(*, action: str | None = None, event_type: str | None = None): + statement = select(AuditEvent).order_by(AuditEvent.id) + if action is not None: + statement = statement.where(AuditEvent.action_id == action) + if event_type is not None: + statement = statement.where(AuditEvent.event_type == event_type) + async with db_session.get_session_factory()() as session: + return list((await session.scalars(statement)).all()) + + +def concealed_error(response: Response) -> dict[str, Any]: + body = response.json() + UUID(body["error"].pop("correlation_id")) + return body + + +def assert_unavailable(response: Response) -> None: + assert response.status_code == 503, response.text + error = response.json()["error"] + assert set(error) == {"code", "message", "retryable", "correlation_id", "details"} + assert error["code"] == "service_unavailable" + assert error["message"] == "Service unavailable" + assert error["retryable"] is True + assert error["details"] == {} + UUID(error["correlation_id"]) diff --git a/backend/tests/authorization/admin_access/test_admin_reads_postgresql.py b/backend/tests/authorization/admin_access/test_admin_reads_postgresql.py new file mode 100644 index 000000000..ba030ad0d --- /dev/null +++ b/backend/tests/authorization/admin_access/test_admin_reads_postgresql.py @@ -0,0 +1,224 @@ +"""Administrative read projections, provenance and observations through real routes.""" + +from datetime import datetime +import json +import logging +from uuid import UUID, uuid4 + +import pytest + +from tests.authorization.admin_access.read_support import ( + LINK_FIELDS, + PROFILE_FIELDS, + READ_ACTIONS, + read_path, + seed_read_target, +) +from tests.authorization.admin_access.support import ( + AdminAccess, + actor_observation, + authority_events, + authority_snapshot, + concealed_error, + seed_old_observation, +) + + +@pytest.mark.parametrize( + "kind,surface", + [ + ("human", "profile"), + ("human", "link"), + ("service", "profile"), + ("service", "link"), + ("suspended", "profile"), + ("revoked_link", "link"), + ], +) +async def test_admin_read_projects_only_public_fields( + admin_access: AdminAccess, + kind: str, + surface: str, + caplog: pytest.LogCaptureFixture, +) -> None: + target = await seed_read_target(admin_access, kind) + caplog.clear() + caplog.set_level(logging.DEBUG, logger="app") + response = await admin_access.signed.client.get( + read_path(target.id, surface), headers=admin_access.admin.headers + ) + assert response.status_code == 200, response.text + body = response.json() + assert set(body) == (PROFILE_FIELDS if surface == "profile" else LINK_FIELDS) + assert body["actor_profile_id"] == str(target.id) + if surface == "profile": + assert body["actor_kind"] == ("service" if kind == "service" else "human") + assert body["service_identity"] == ( + "workstream.artifact.verifier" if kind == "service" else None + ) + if kind == "service": + assert body["last_seen_at" if surface == "profile" else "last_verified_at"] is None + assert ( + body["status"] + == { + "human": "active", + "service": "active", + "suspended": "suspended", + "revoked_link": "revoked", + }[kind] + ) + serialized = json.dumps(body, sort_keys=True) + for value in target.private_values: + assert value not in serialized + assert value not in caplog.text + + +@pytest.mark.parametrize("surface", ["profile", "link"]) +async def test_admin_read_touches_caller_not_target( + admin_access: AdminAccess, surface: str +) -> None: + access = admin_access + caller_before = await seed_old_observation(access.admin.id) + target_before = await seed_old_observation(access.target.id) + response = await access.signed.client.get( + read_path(access.target.id, surface), headers=access.admin.headers + ) + assert response.status_code == 200, response.text + assert await actor_observation(access.target.id) == target_before + caller_after = await actor_observation(access.admin.id) + assert caller_after.last_seen_at > caller_before.last_seen_at + assert caller_after.last_verified_at > caller_before.last_verified_at + + +@pytest.mark.parametrize("surface", ["profile", "link"]) +async def test_admin_read_records_exact_authorization_provenance( + admin_access: AdminAccess, + surface: str, +) -> None: + access = admin_access + response = await access.signed.client.get( + read_path(access.target.id, surface), headers=access.admin.headers + ) + assert response.status_code == 200, response.text + action, permission = READ_ACTIONS[surface] + events = await authority_events(action=action, event_type="SensitiveAuthorizationAllowed") + assert len(events) == 1 + event = events[0] + assert event.permission_id == permission + assert event.actor_id == str(access.admin.id) + assert event.resource_id == str(access.target.id) + assert event.target_actor_ref == str(access.target.id) + assert event.target_ref_id == str(access.target.id) + assert event.matched_grant_id == access.bootstrap_grant_id + assert event.project_id is None + assert event.after_facts == {"allowed": True} + assert UUID(str(event.request_id)) == UUID(response.headers["x-request-id"]) + assert UUID(str(event.correlation_id)) == UUID(response.headers["x-correlation-id"]) + + +async def test_self_admin_profile_read_returns_committed_observation( + admin_access: AdminAccess, +) -> None: + access = admin_access + before = await seed_old_observation(access.admin.id) + authority_before = await authority_snapshot() + response = await access.signed.client.get( + read_path(access.admin.id, "profile"), headers=access.admin.headers + ) + assert response.status_code == 200, response.text + after = await actor_observation(access.admin.id) + assert after.updated_at > before.updated_at + assert after.last_seen_at > before.last_seen_at + assert after.last_verified_at > before.last_verified_at + assert datetime.fromisoformat(response.json()["updated_at"]) == after.updated_at + assert datetime.fromisoformat(response.json()["last_seen_at"]) == after.last_seen_at + authority_after = await authority_snapshot() + assert authority_after["admin_role_grants"] == authority_before["admin_role_grants"] + assert ( + authority_after["authority_idempotency_records"] + == authority_before["authority_idempotency_records"] + ) + assert len(authority_after["audit_events"]) == len(authority_before["audit_events"]) + 1 + + +async def test_self_admin_link_read_returns_committed_observation( + admin_access: AdminAccess, +) -> None: + access = admin_access + before = await seed_old_observation(access.admin.id) + authority_before = await authority_snapshot() + response = await access.signed.client.get( + read_path(access.admin.id, "link"), headers=access.admin.headers + ) + assert response.status_code == 200, response.text + after = await actor_observation(access.admin.id) + assert after.updated_at > before.updated_at + assert after.last_seen_at > before.last_seen_at + assert after.last_verified_at > before.last_verified_at + assert datetime.fromisoformat(response.json()["last_verified_at"]) == after.last_verified_at + authority_after = await authority_snapshot() + assert authority_after["admin_role_grants"] == authority_before["admin_role_grants"] + assert ( + authority_after["authority_idempotency_records"] + == authority_before["authority_idempotency_records"] + ) + assert len(authority_after["audit_events"]) == len(authority_before["audit_events"]) + 1 + + +async def test_missing_admin_target_has_concealed_response_and_no_success_effect( + admin_access: AdminAccess, +) -> None: + access = admin_access + observed = await actor_observation(access.admin.id) + before = await authority_snapshot() + absent = uuid4() + profile = await access.signed.client.get( + read_path(absent, "profile"), headers=access.admin.headers + ) + link = await access.signed.client.get(read_path(absent, "link"), headers=access.admin.headers) + assert profile.status_code == link.status_code == 404 + assert concealed_error(profile) == concealed_error(link) + assert profile.json()["error"]["code"] == "actor_resource_not_found" + assert await actor_observation(access.admin.id) == observed + assert await authority_snapshot() == before + + +@pytest.mark.parametrize("surface,total", [("permissions", 73), ("admin-role-definitions", 5)]) +async def test_admin_catalogue_read_returns_public_definitions( + admin_access: AdminAccess, + surface: str, + total: int, +) -> None: + access = admin_access + before = await seed_old_observation(access.admin.id) + response = await access.signed.client.get( + f"/api/v1/authorization/{surface}", headers=access.admin.headers + ) + assert response.status_code == 200, response.text + assert (response.json()["total"], len(response.json()["items"])) == (total, total) + if surface == "admin-role-definitions": + assert [item["role"] for item in response.json()["items"]] == [ + "access_administrator", + "operator", + "project_manager", + "finance_authority", + "audit_authority", + ] + after = await actor_observation(access.admin.id) + assert after.last_seen_at > before.last_seen_at + assert after.last_verified_at > before.last_verified_at + + +async def test_admin_self_patch_commits_requested_observation(admin_access: AdminAccess) -> None: + access = admin_access + before = await seed_old_observation(access.admin.id) + response = await access.signed.client.patch( + "/api/v1/actors/me", + headers=access.admin.headers, + json={"display_name": "Administrator observation"}, + ) + assert response.status_code == 200, response.text + after = await actor_observation(access.admin.id) + assert after.display_name == "Administrator observation" + assert after.last_seen_at > before.last_seen_at + assert after.last_verified_at > before.last_verified_at diff --git a/backend/tests/authorization/admin_access/test_api_journey.py b/backend/tests/authorization/admin_access/test_api_journey.py new file mode 100644 index 000000000..b9bdb2e34 --- /dev/null +++ b/backend/tests/authorization/admin_access/test_api_journey.py @@ -0,0 +1,21 @@ +"""One connected signed API journey, not every validation variation.""" + +from scripts.bootstrap_access_administrator import _run as run_bootstrap +from tests.authorization.admin_access.support import SignedAccess + + +async def test_signed_admin_grant_journey(signed_access: SignedAccess) -> None: + admin = await signed_access.actor("administrator", roles=("viewer",)) + target = await signed_access.actor("target", roles=("admin",)) + code, bootstrap = await run_bootstrap(admin.id, execute=True) + assert code == 0, bootstrap + grant_id = await signed_access.grant(admin, target) + assigned = await signed_access.client.get("/api/v1/actors/me", headers=target.headers) + assert assigned.status_code == 200, assigned.text + assert assigned.json()["admin_roles"] == ["operator"] + revoked = await signed_access.revoke(admin, grant_id) + assert revoked.status_code == 200, revoked.text + assert revoked.json()["version"] == 2 + observed = await signed_access.client.get("/api/v1/actors/me", headers=target.headers) + assert observed.status_code == 200, observed.text + assert observed.json()["admin_roles"] == [] diff --git a/backend/tests/authorization/admin_access/test_bootstrap_postgresql.py b/backend/tests/authorization/admin_access/test_bootstrap_postgresql.py new file mode 100644 index 000000000..c0cea3050 --- /dev/null +++ b/backend/tests/authorization/admin_access/test_bootstrap_postgresql.py @@ -0,0 +1,77 @@ +"""Bootstrap and signed-token authority at the real persistence boundary.""" + +from scripts.bootstrap_access_administrator import _run as run_bootstrap +from tests.authorization.admin_access.support import ( + AdminAccess, + SignedAccess, + actor_observation, + authority_events, + authority_snapshot, +) + + +async def test_token_role_cannot_read_authorization_catalogue(signed_access: SignedAccess) -> None: + actor = await signed_access.actor("untrusted-admin-role", roles=("admin",)) + before = await authority_snapshot() + response = await signed_access.client.get( + "/api/v1/authorization/permissions", headers=actor.headers + ) + assert response.status_code == 403, response.text + assert response.json()["error"]["code"] == "permission_not_granted" + after = await authority_snapshot() + assert {k: v for k, v in after.items() if k != "audit_events"} == { + k: v for k, v in before.items() if k != "audit_events" + } + assert ( + await authority_events( + action="authorization.permission_catalogue.read", + event_type="SensitiveAuthorizationAllowed", + ) + == [] + ) + + +async def test_bootstrap_dry_run_leaves_control_grants_and_events_unchanged( + signed_access: SignedAccess, +) -> None: + actor = await signed_access.actor("bootstrap-candidate") + before = await authority_snapshot() + observed = await actor_observation(actor.id) + code, result = await run_bootstrap(actor.id, execute=False) + assert code == 0 + assert result == { + "result_code": "eligible", + "actor_profile_id": str(actor.id), + "would_change": True, + } + assert await authority_snapshot() == before + assert await actor_observation(actor.id) == observed + + +async def test_later_bootstrap_returns_audited_original_grant_conflict( + admin_access: AdminAccess, +) -> None: + access = admin_access + before = await authority_snapshot() + code, result = await run_bootstrap(access.target.id, execute=True) + assert code == 3 + assert result == { + "result_code": "admin_role_grant_exists", + "actor_profile_id": str(access.target.id), + "grant_id": access.bootstrap_grant_id, + "changed": False, + } + after = await authority_snapshot() + assert {k: v for k, v in after.items() if k != "audit_events"} == { + k: v for k, v in before.items() if k != "audit_events" + } + before_ids = {row["id"] for row in before["audit_events"]} + added = [row for row in after["audit_events"] if row["id"] not in before_ids] + assert len(added) == 1 + event = added[0] + assert event["event_type"] == "AdminRoleGrantIssueDenied" + assert event["actor_id"] == "workstream:system:bootstrap" + assert event["entity_id"] == access.bootstrap_grant_id + assert event["target_actor_ref"] == str(access.target.id) + assert event["denial_code"] == "admin_role_grant_exists" + assert len(await authority_events(event_type="InitialAccessAdministratorBootstrapped")) == 1 diff --git a/backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py b/backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py new file mode 100644 index 000000000..502e0afad --- /dev/null +++ b/backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py @@ -0,0 +1,154 @@ +"""Actual staged effects and fresh-session rollback, not label-only failures.""" + +from uuid import uuid4 + +import pytest + +from tests.authorization.admin_access.fault_support import fail_admin_read, fail_next_commit +from tests.authorization.admin_access.read_support import READ_ACTIONS, read_path +from tests.authorization.admin_access.support import ( + AdminAccess, + actor_observation, + assert_unavailable, + authority_snapshot, + grant_body, + seed_old_observation, +) + + +@pytest.mark.parametrize("surface", ["profile", "link"]) +@pytest.mark.parametrize("stage", ["evidence", "lookup", "touch", "commit"]) +async def test_admin_read_failure_rolls_back_staged_effects( + admin_access: AdminAccess, + monkeypatch: pytest.MonkeyPatch, + surface: str, + stage: str, +) -> None: + access = admin_access + before_actor = await seed_old_observation(access.admin.id) + before = await authority_snapshot() + probe = fail_admin_read(monkeypatch, access.admin.id, surface, stage) + response = await access.signed.client.get( + read_path(access.target.id, surface), headers=access.admin.headers + ) + assert_unavailable(response) + assert probe.rows is not None, "failure must reach the claimed transaction stage" + action, _ = READ_ACTIONS[surface] + staged = [e for e in probe.rows["audit_events"] if e["action_id"] == action] + assert len(staged) == (0 if stage == "evidence" else 1) + if staged: + assert staged[0]["event_type"] == "SensitiveAuthorizationAllowed" + assert staged[0]["resource_id"] == str(access.target.id) + assert probe.actor is not None + if stage == "commit": + assert probe.actor.last_seen_at > before_actor.last_seen_at + assert probe.actor.last_verified_at > before_actor.last_verified_at + else: + assert probe.actor == before_actor + assert await authority_snapshot() == before + assert await actor_observation(access.admin.id) == before_actor + + +async def test_catalogue_read_commit_failure_rolls_back_observation( + admin_access: AdminAccess, + monkeypatch: pytest.MonkeyPatch, +) -> None: + access = admin_access + before_actor = await seed_old_observation(access.admin.id) + before = await authority_snapshot() + probe = fail_next_commit(monkeypatch, access.admin.id) + response = await access.signed.client.get( + "/api/v1/authorization/permissions", headers=access.admin.headers + ) + assert_unavailable(response) + assert probe.actor is not None + assert probe.actor.last_seen_at > before_actor.last_seen_at + assert probe.actor.last_verified_at > before_actor.last_verified_at + assert probe.rows is not None + assert any( + e["action_id"] == "authorization.permission_catalogue.read" + and e["event_type"] == "SensitiveAuthorizationAllowed" + for e in probe.rows["audit_events"] + ) + assert await authority_snapshot() == before + assert await actor_observation(access.admin.id) == before_actor + + +async def test_admin_self_patch_commit_failure_rolls_back( + admin_access: AdminAccess, + monkeypatch: pytest.MonkeyPatch, +) -> None: + access = admin_access + before_actor = await seed_old_observation(access.admin.id) + before = await authority_snapshot() + probe = fail_next_commit(monkeypatch, access.admin.id) + response = await access.signed.client.patch( + "/api/v1/actors/me", + headers=access.admin.headers, + json={"display_name": "Must roll back"}, + ) + assert_unavailable(response) + assert probe.actor is not None + assert probe.actor.display_name == "Must roll back" + assert probe.actor.last_seen_at > before_actor.last_seen_at + assert probe.actor.last_verified_at > before_actor.last_verified_at + assert probe.rows is not None + assert any(e["action_id"] == "actor.profile.update_self" for e in probe.rows["audit_events"]) + assert await authority_snapshot() == before + assert await actor_observation(access.admin.id) == before_actor + + +@pytest.mark.parametrize("operation", ["issue", "revoke"]) +async def test_grant_mutation_commit_failure_rolls_back( + admin_access: AdminAccess, + monkeypatch: pytest.MonkeyPatch, + operation: str, +) -> None: + access = admin_access + body = grant_body(access.target.id) + grant_id = ( + await access.signed.grant(access.admin, access.target) if operation == "revoke" else None + ) + before_actor = await seed_old_observation(access.admin.id) + before = await authority_snapshot() + key = str(uuid4()) + probe = fail_next_commit(monkeypatch, access.admin.id) + if operation == "issue": + response = await access.signed.issue(access.admin, body, key=key) + else: + response = await access.signed.revoke(access.admin, grant_id, key=key) + assert_unavailable(response) + assert probe.rows is not None + grants = [ + r + for r in probe.rows["admin_role_grants"] + if r["target_actor_profile_id"] == str(access.target.id) + ] + assert len(grants) == 1 + assert grants[0]["status"] == ("active" if operation == "issue" else "revoked") + assert grants[0]["version"] == (1 if operation == "issue" else 2) + events = [ + e + for e in probe.rows["audit_events"] + if e["entity_id"] == str(grants[0]["id"]) + and e["event_type"] + == ("AdminRoleGrantIssued" if operation == "issue" else "AdminRoleGrantRevoked") + ] + assert len(events) == 1 + assert ( + sum( + e["invalidation_cause_event_id"] == str(events[0]["id"]) + for e in probe.rows["audit_events"] + ) + == 1 + ) + assert probe.actor is not None + assert probe.actor.last_seen_at > before_actor.last_seen_at + assert probe.actor.last_verified_at > before_actor.last_verified_at + assert await authority_snapshot() == before + assert await actor_observation(access.admin.id) == before_actor + if operation == "issue": + retried = await access.signed.issue(access.admin, body, key=key) + else: + retried = await access.signed.revoke(access.admin, grant_id, key=key) + assert retried.status_code == (201 if operation == "issue" else 200), retried.text diff --git a/backend/tests/authorization/admin_access/test_grant_api_postgresql.py b/backend/tests/authorization/admin_access/test_grant_api_postgresql.py new file mode 100644 index 000000000..d4fa85576 --- /dev/null +++ b/backend/tests/authorization/admin_access/test_grant_api_postgresql.py @@ -0,0 +1,273 @@ +"""Grant commands: real operation recovery, eligibility and caller isolation.""" + +from uuid import uuid4 + +import pytest + +from tests.authorization.admin_access.read_support import seed_read_target +from tests.authorization.admin_access.support import ( + AdminAccess, + actor_observation, + authority_snapshot, + concealed_error, + create_project, + grant_body, + seed_old_observation, +) + + +@pytest.mark.parametrize( + "operation,role,project_scoped", + [ + ("issue", "operator", False), + ("issue", "project_manager", True), + ("issue", "audit_authority", True), + ("issue", "audit_authority", False), + ("revoke", "operator", False), + ], +) +async def test_grant_mutation_exact_replay_has_one_effect( + admin_access: AdminAccess, + operation: str, + role: str, + project_scoped: bool, +) -> None: + access = admin_access + project = await create_project("Grant recovery") if project_scoped else None + body = grant_body(access.target.id, role=role, project_id=project) + grant_id = ( + await access.signed.grant(access.admin, access.target) if operation == "revoke" else None + ) + before_actor = await seed_old_observation(access.admin.id) + before = await authority_snapshot() + key = str(uuid4()) + if operation == "issue": + first = await access.signed.issue(access.admin, body, key=key) + replay = await access.signed.issue(access.admin, body, key=key) + else: + assert grant_id is not None + first = await access.signed.revoke(access.admin, grant_id, key=key) + replay = await access.signed.revoke(access.admin, grant_id, key=key) + assert first.status_code == replay.status_code == (201 if operation == "issue" else 200) + assert first.json() == replay.json() + assert first.json()["version"] == (1 if operation == "issue" else 2) + after_actor = await actor_observation(access.admin.id) + assert after_actor.last_seen_at > before_actor.last_seen_at + assert after_actor.last_verified_at > before_actor.last_verified_at + after = await authority_snapshot() + records = [ + r for r in after["authority_idempotency_records"] if str(r["idempotency_key"]) == key + ] + assert len(records) == 1 + assert records[0]["operation"] == f"admin_role_grant.{operation}" + assert records[0]["status"] == "committed" + assert str(records[0]["response_resource_id"]) == first.json()["resource_id"] + assert records[0]["response_resource_version"] == first.json()["version"] + old_events = {r["id"] for r in before["audit_events"]} + events = [r for r in after["audit_events"] if r["id"] not in old_events] + success = [ + e + for e in events + if e["event_type"] + == ("AdminRoleGrantIssued" if operation == "issue" else "AdminRoleGrantRevoked") + ] + assert len(success) == 1 + assert success[0]["entity_id"] == first.json()["resource_id"] + assert success[0]["actor_ref"] == str(access.admin.id) + assert str(success[0]["idempotency_reference"]) == str(records[0]["id"]) + invalidations = [e for e in events if e["event_type"] == "AuthorityInvalidationRequested"] + assert len(invalidations) == 1 + assert invalidations[0]["invalidation_cause_event_id"] == success[0]["id"] + assert len(after["admin_role_grants"]) == len(before["admin_role_grants"]) + ( + operation == "issue" + ) + + +async def test_same_caller_key_is_isolated_by_grant_operation(admin_access: AdminAccess) -> None: + access = admin_access + key = str(uuid4()) + issued = await access.signed.issue(access.admin, grant_body(access.target.id), key=key) + assert issued.status_code == 201, issued.text + grant_id = issued.json()["resource_id"] + revoked = await access.signed.revoke(access.admin, grant_id, key=key) + assert revoked.status_code == 200, revoked.text + assert revoked.json()["resource_id"] == grant_id + assert revoked.json()["version"] == 2 + rows = await authority_snapshot() + records = [r for r in rows["authority_idempotency_records"] if str(r["idempotency_key"]) == key] + assert len(records) == 2 + assert { + (r["actor_ref"], r["operation"], r["response_resource_version"], r["response_http_status"]) + for r in records + } == { + (str(access.admin.id), "admin_role_grant.issue", 1, 201), + (str(access.admin.id), "admin_role_grant.revoke", 2, 200), + } + assert {str(r["response_resource_id"]) for r in records} == {grant_id} + assert {r["status"] for r in records} == {"committed"} + for record in records: + events = [ + e for e in rows["audit_events"] if str(e["idempotency_reference"]) == str(record["id"]) + ] + event_type = ( + "AdminRoleGrantIssued" + if record["operation"].endswith("issue") + else "AdminRoleGrantRevoked" + ) + success = [e for e in events if e["event_type"] == event_type] + assert len(success) == 1 + assert success[0]["entity_id"] == grant_id + assert sum(e["invalidation_cause_event_id"] == success[0]["id"] for e in events) == 1 + grant = next(r for r in rows["admin_role_grants"] if str(r["id"]) == grant_id) + assert (grant["status"], grant["version"]) == ("revoked", 2) + + +@pytest.mark.parametrize("operation", ["issue", "revoke"]) +async def test_grant_mutation_mismatch_preserves_product_state( + admin_access: AdminAccess, + operation: str, +) -> None: + access = admin_access + key = str(uuid4()) + if operation == "issue": + first = await access.signed.issue(access.admin, grant_body(access.target.id), key=key) + else: + grant_id = await access.signed.grant(access.admin, access.target) + first = await access.signed.revoke(access.admin, grant_id, key=key) + assert first.status_code == (201 if operation == "issue" else 200) + before = await authority_snapshot() + if operation == "issue": + response = await access.signed.issue( + access.admin, + grant_body(access.target.id) | {"reason": "Changed request"}, + key=key, + ) + else: + response = await access.signed.revoke( + access.admin, + first.json()["resource_id"], + key=key, + reason="Changed request", + ) + assert response.status_code == 409 + assert response.json()["error"]["code"] == "idempotency_mismatch" + after = await authority_snapshot() + assert {k: v for k, v in after.items() if k != "audit_events"} == { + k: v for k, v in before.items() if k != "audit_events" + } + prior = {e["id"] for e in before["audit_events"]} + added = [e for e in after["audit_events"] if e["id"] not in prior] + assert len(added) == 1 + assert added[0]["event_type"] == "SensitiveAuthorizationDenied" + assert added[0]["denial_code"] == "idempotency_mismatch" + assert added[0]["actor_ref"] == str(access.admin.id) + assert added[0]["action_id"] == f"admin_role_grant.{operation}" + + +async def test_distinct_operation_duplicate_grant_is_conflict(admin_access: AdminAccess) -> None: + access = admin_access + await access.signed.grant(access.admin, access.target) + before = await authority_snapshot() + response = await access.signed.issue(access.admin, grant_body(access.target.id)) + assert response.status_code == 409 + assert response.json()["error"]["code"] == "admin_role_grant_exists" + after = await authority_snapshot() + assert after["admin_role_grants"] == before["admin_role_grants"] + assert after["authority_idempotency_records"] == before["authority_idempotency_records"] + assert not any( + e["event_type"] == "AdminRoleGrantIssued" and e not in before["audit_events"] + for e in after["audit_events"] + ) + + +@pytest.mark.parametrize("kind", ["service", "suspended", "revoked_link"]) +async def test_ineligible_grant_targets_share_missing_response( + admin_access: AdminAccess, + kind: str, +) -> None: + access = admin_access + target = await seed_read_target(access, kind) + before = await authority_snapshot() + absent = await access.signed.issue(access.admin, grant_body(uuid4())) + ineligible = await access.signed.issue(access.admin, grant_body(target.id)) + assert absent.status_code == ineligible.status_code == 404 + assert concealed_error(absent) == concealed_error(ineligible) + assert ineligible.json()["error"]["code"] == "actor_not_found" + error = ineligible.json() + assert (error["detail"], error["error"]["message"], error["error"]["retryable"]) == ( + "Actor not found", + "Actor not found", + False, + ) + after = await authority_snapshot() + assert after["authority_control"] == before["authority_control"] + assert after["admin_role_grants"] == before["admin_role_grants"] + assert after["authority_idempotency_records"] == before["authority_idempotency_records"] + + +async def test_self_admin_grant_is_denied_without_grant(admin_access: AdminAccess) -> None: + access = admin_access + before = await authority_snapshot() + response = await access.signed.issue(access.admin, grant_body(access.admin.id)) + assert response.status_code == 403 + assert response.json()["error"]["code"] == "self_grant_forbidden" + after = await authority_snapshot() + assert after["admin_role_grants"] == before["admin_role_grants"] + assert after["authority_idempotency_records"] == before["authority_idempotency_records"] + + +async def test_self_admin_revoke_preserves_grant(admin_access: AdminAccess) -> None: + access = admin_access + before = await authority_snapshot() + response = await access.signed.revoke(access.admin, access.bootstrap_grant_id) + assert response.status_code == 403 + assert response.json()["error"]["code"] == "self_role_revoke_forbidden" + after = await authority_snapshot() + assert after["admin_role_grants"] == before["admin_role_grants"] + assert after["authority_idempotency_records"] == before["authority_idempotency_records"] + + +async def test_revoked_and_absent_grants_share_concealed_revoke_response( + admin_access: AdminAccess, +) -> None: + access = admin_access + grant_id = await access.signed.grant(access.admin, access.target) + first = await access.signed.revoke(access.admin, grant_id) + assert first.status_code == 200 + before = await authority_snapshot() + revoked = await access.signed.revoke(access.admin, grant_id) + absent = await access.signed.revoke(access.admin, str(uuid4())) + assert revoked.status_code == absent.status_code == 404 + assert concealed_error(revoked) == concealed_error(absent) + assert revoked.json()["error"]["code"] == "grant_not_found" + after = await authority_snapshot() + assert after["admin_role_grants"] == before["admin_role_grants"] + assert after["authority_idempotency_records"] == before["authority_idempotency_records"] + assert [e for e in after["audit_events"] if e["event_type"] == "AdminRoleGrantRevoked"] == [ + e for e in before["audit_events"] if e["event_type"] == "AdminRoleGrantRevoked" + ] + + +async def test_target_role_projection_does_not_grant_catalogue_access( + admin_access: AdminAccess, +) -> None: + access = admin_access + project = await create_project("Role projection") + await access.signed.grant( + access.admin, access.target, role="project_manager", project_id=project + ) + operator = await access.signed.grant(access.admin, access.target) + own = await access.signed.client.get("/api/v1/actors/me", headers=access.target.headers) + assert own.status_code == 200 + assert own.json()["admin_roles"] == ["operator", "project_manager"] + definitions = await access.signed.client.get( + "/api/v1/authorization/admin-role-definitions", + headers=access.target.headers, + ) + assert definitions.status_code == 403 + assert definitions.json()["error"]["code"] == "permission_not_granted" + revoked = await access.signed.revoke(access.admin, operator) + assert revoked.status_code == 200 + own = await access.signed.client.get("/api/v1/actors/me", headers=access.target.headers) + assert own.status_code == 200 + assert own.json()["admin_roles"] == ["project_manager"] diff --git a/backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py b/backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py new file mode 100644 index 000000000..7ebbe0f71 --- /dev/null +++ b/backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py @@ -0,0 +1,245 @@ +"""Actual reservation/control contention and serialized authority outcomes.""" + +from uuid import uuid4 + +import pytest + +from scripts.bootstrap_access_administrator import _run as run_bootstrap +from tests.authorization.admin_access.concurrency_support import ordered_owner_calls +from tests.authorization.admin_access.support import ( + AdminAccess, + SignedAccess, + authority_snapshot, + create_project, + grant_body, +) + + +async def test_concurrent_bootstrap_has_one_persisted_winner( + signed_access: SignedAccess, + auth_database_env: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + first = await signed_access.actor("bootstrap-first") + second = await signed_access.actor("bootstrap-second") + won, lost, custody = await ordered_owner_calls( + lambda: run_bootstrap(first.id, execute=True), + lambda: run_bootstrap(second.id, execute=True), + boundary="control", + database_url=auth_database_env, + monkeypatch=monkeypatch, + ) + assert custody.observed + assert (won[0], lost[0]) == (0, 3) + assert lost[1]["grant_id"] == won[1]["grant_id"] + rows = await authority_snapshot() + assert len(rows["admin_role_grants"]) == 1 + grant = rows["admin_role_grants"][0] + assert str(grant["id"]) == won[1]["grant_id"] + assert grant["target_actor_profile_id"] == str(first.id) + assert (grant["status"], grant["version"]) == ("active", 1) + assert len(rows["authority_control"]) == 1 + assert rows["authority_control"][0]["bootstrap_completed"] is True + events = [ + e + for e in rows["audit_events"] + if e["event_type"] == "InitialAccessAdministratorBootstrapped" + ] + assert len(events) == 1 + assert events[0]["entity_id"] == won[1]["grant_id"] + conflicts = [e for e in rows["audit_events"] if e["event_type"] == "AdminRoleGrantIssueDenied"] + assert len(conflicts) == 1 + assert conflicts[0]["target_actor_ref"] == str(second.id) + + +async def test_concurrent_same_key_grant_returns_one_result( + admin_access: AdminAccess, + auth_database_env: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + access = admin_access + key = str(uuid4()) + body = grant_body(access.target.id) + first, second, custody = await ordered_owner_calls( + lambda: access.signed.issue(access.admin, body, key=key), + lambda: access.signed.issue(access.admin, body, key=key), + boundary="reservation", + database_url=auth_database_env, + monkeypatch=monkeypatch, + ) + assert custody.observed + assert first.status_code == second.status_code == 201 + assert first.json() == second.json() + rows = await authority_snapshot() + grants = [ + r + for r in rows["admin_role_grants"] + if r["target_actor_profile_id"] == str(access.target.id) + ] + assert len(grants) == 1 + assert str(grants[0]["id"]) == first.json()["resource_id"] + records = [r for r in rows["authority_idempotency_records"] if str(r["idempotency_key"]) == key] + assert len(records) == 1 + events = [ + e for e in rows["audit_events"] if str(e["idempotency_reference"]) == str(records[0]["id"]) + ] + success = [e for e in events if e["event_type"] == "AdminRoleGrantIssued"] + assert len(success) == 1 + assert sum(e["invalidation_cause_event_id"] == success[0]["id"] for e in events) == 1 + + +async def test_concurrent_distinct_keys_create_one_active_grant( + admin_access: AdminAccess, + auth_database_env: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + access = admin_access + body = grant_body(access.target.id) + first_key, second_key = str(uuid4()), str(uuid4()) + first, second, custody = await ordered_owner_calls( + lambda: access.signed.issue(access.admin, body, key=first_key), + lambda: access.signed.issue(access.admin, body, key=second_key), + boundary="control", + database_url=auth_database_env, + monkeypatch=monkeypatch, + ) + assert custody.observed + assert (first.status_code, second.status_code) == (201, 409) + assert second.json()["error"]["code"] == "admin_role_grant_exists" + rows = await authority_snapshot() + grants = [ + r + for r in rows["admin_role_grants"] + if r["target_actor_profile_id"] == str(access.target.id) + ] + assert len(grants) == 1 + assert (grants[0]["status"], grants[0]["version"]) == ("active", 1) + records = [ + r + for r in rows["authority_idempotency_records"] + if str(r["idempotency_key"]) in {first_key, second_key} + ] + assert [str(r["idempotency_key"]) for r in records] == [first_key] + assert sum(e["event_type"] == "AdminRoleGrantIssued" for e in rows["audit_events"]) == 1 + assert sum(e["event_type"] == "AdminRoleGrantIssueDenied" for e in rows["audit_events"]) == 1 + + +async def test_cross_revoke_retains_one_effective_admin( + admin_access: AdminAccess, + auth_database_env: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + access = admin_access + second_grant = await access.signed.grant( + access.admin, access.target, role="access_administrator" + ) + first, second, custody = await ordered_owner_calls( + lambda: access.signed.revoke(access.admin, second_grant), + lambda: access.signed.revoke(access.target, access.bootstrap_grant_id), + boundary="control", + database_url=auth_database_env, + monkeypatch=monkeypatch, + ) + assert custody.observed + assert (first.status_code, second.status_code) == (200, 403) + assert second.json()["error"]["code"] == "permission_not_granted" + rows = await authority_snapshot() + active = [ + r + for r in rows["admin_role_grants"] + if r["role"] == "access_administrator" and r["status"] == "active" + ] + assert [str(r["id"]) for r in active] == [access.bootstrap_grant_id] + events = [e for e in rows["audit_events"] if e["event_type"] == "AdminRoleGrantRevoked"] + assert len(events) == 1 + assert events[0]["entity_id"] == second_grant + assert ( + sum(e["invalidation_cause_event_id"] == events[0]["id"] for e in rows["audit_events"]) == 1 + ) + + +@pytest.mark.parametrize("first_operation", ["issue", "revoke"]) +async def test_issue_against_revocation_obeys_lock_order( + admin_access: AdminAccess, + auth_database_env: str, + monkeypatch: pytest.MonkeyPatch, + first_operation: str, +) -> None: + access = admin_access + second_grant = await access.signed.grant( + access.admin, access.target, role="access_administrator" + ) + recipient = await access.signed.actor("project-manager-recipient") + project = await create_project("Serialized project authority") + issue_key, revoke_key = str(uuid4()), str(uuid4()) + calls = { + "issue": lambda: access.signed.issue( + access.target, + grant_body(recipient.id, role="project_manager", project_id=project), + key=issue_key, + ), + "revoke": lambda: access.signed.revoke(access.admin, second_grant, key=revoke_key), + } + second_operation = "revoke" if first_operation == "issue" else "issue" + first, second, custody = await ordered_owner_calls( + calls[first_operation], + calls[second_operation], + boundary="control", + database_url=auth_database_env, + monkeypatch=monkeypatch, + ) + assert custody.observed + responses = {first_operation: first, second_operation: second} + assert responses["revoke"].status_code == 200 + assert responses["issue"].status_code == (201 if first_operation == "issue" else 403) + if first_operation == "revoke": + assert responses["issue"].json()["error"]["code"] == "permission_not_granted" + rows = await authority_snapshot() + grants = [ + r for r in rows["admin_role_grants"] if r["target_actor_profile_id"] == str(recipient.id) + ] + assert len(grants) == (1 if first_operation == "issue" else 0) + events = [ + e + for e in rows["audit_events"] + if e["event_type"] == "AdminRoleGrantIssued" and e["target_actor_ref"] == str(recipient.id) + ] + assert len(events) == len(grants) + records = [ + r for r in rows["authority_idempotency_records"] if str(r["idempotency_key"]) == issue_key + ] + assert len(records) == len(grants) + if events: + assert events[0]["entity_id"] == str(grants[0]["id"]) + assert ( + sum(e["invalidation_cause_event_id"] == events[0]["id"] for e in rows["audit_events"]) + == 1 + ) + revoked = next(r for r in rows["admin_role_grants"] if str(r["id"]) == second_grant) + assert revoked["status"] == "revoked" + revoke_events = [ + e + for e in rows["audit_events"] + if e["event_type"] == "AdminRoleGrantRevoked" and e["entity_id"] == second_grant + ] + assert len(revoke_events) == 1 + assert ( + sum( + e["invalidation_cause_event_id"] == revoke_events[0]["id"] for e in rows["audit_events"] + ) + == 1 + ) + if first_operation == "revoke": + denied = [ + e + for e in rows["audit_events"] + if e["event_type"] == "SensitiveAuthorizationDenied" + and e["action_id"] == "admin_role_grant.issue" + and e["resource_id"] == str(recipient.id) + ] + assert len(denied) == 1 + assert not any( + e["event_type"] == "AuthorityInvalidationRequested" + and e["invalidation_target_ref"] == str(recipient.id) + for e in rows["audit_events"] + ) diff --git a/backend/tests/authorization/admin_access/test_grant_reads_postgresql.py b/backend/tests/authorization/admin_access/test_grant_reads_postgresql.py new file mode 100644 index 000000000..5fa5d3673 --- /dev/null +++ b/backend/tests/authorization/admin_access/test_grant_reads_postgresql.py @@ -0,0 +1,198 @@ +"""Grant query disclosure follows actual system or exact-project authority.""" + +import json + +import pytest + +from tests.authorization.admin_access.read_support import read_path +from tests.authorization.admin_access.support import ( + AdminAccess, + authority_snapshot, + create_project, + grant_body, +) + + +@pytest.mark.parametrize("surface", ["list", "history", "foreign", "profile", "link"]) +async def test_project_auditor_reads_only_granted_project( + admin_access: AdminAccess, surface: str +) -> None: + access = admin_access + auditor = await access.signed.actor("project-auditor") + project = await create_project("Authorized project") + foreign = await create_project("Foreign project") + target_grant = await access.signed.grant( + access.admin, access.target, role="project_manager", project_id=project + ) + audit_grant = await access.signed.grant( + access.admin, auditor, role="audit_authority", project_id=project + ) + await access.signed.grant( + access.admin, access.target, role="project_manager", project_id=foreign + ) + path = "/api/v1/admin-role-grants" + params = {"scope_type": "project", "scope_project_id": str(project)} + if surface == "history": + path = f"/api/v1/actors/{access.target.id}/admin-role-grants" + elif surface == "foreign": + params["scope_project_id"] = str(foreign) + elif surface in {"profile", "link"}: + path, params = read_path(access.target.id, surface), {} + response = await access.signed.client.get(path, headers=auditor.headers, params=params) + if surface in {"list", "history"}: + assert response.status_code == 200, response.text + expected = {target_grant, audit_grant} if surface == "list" else {target_grant} + assert response.json()["total"] == len(expected) + assert {r["grant_id"] for r in response.json()["items"]} == expected + assert {r["scope_project_id"] for r in response.json()["items"]} == {str(project)} + if surface == "history": + assert response.json()["items"][0]["target_actor_profile_id"] == str(access.target.id) + else: + assert response.status_code == 403 + assert response.json()["error"]["code"] == ( + "scope_not_authorized" if surface == "foreign" else "permission_not_granted" + ) + + +async def test_audit_authority_cannot_issue_grant(admin_access: AdminAccess) -> None: + access = admin_access + auditor = await access.signed.actor("read-only-auditor") + project = await create_project("Audited project") + await access.signed.grant(access.admin, auditor, role="audit_authority", project_id=project) + before = await authority_snapshot() + response = await access.signed.issue(auditor, grant_body(auditor.id)) + assert response.status_code == 403 + assert response.json()["error"]["code"] == "permission_not_granted" + after = await authority_snapshot() + assert after["admin_role_grants"] == before["admin_role_grants"] + assert after["authority_idempotency_records"] == before["authority_idempotency_records"] + + +@pytest.mark.parametrize( + "surface", ["permissions", "definitions", "list", "history", "profile", "link"] +) +async def test_system_auditor_has_exact_read_surface( + admin_access: AdminAccess, surface: str +) -> None: + access = admin_access + auditor = await access.signed.actor("system-auditor") + grant_id = await access.signed.grant(access.admin, auditor, role="audit_authority") + paths = { + "permissions": "/api/v1/authorization/permissions", + "definitions": "/api/v1/authorization/admin-role-definitions", + "list": "/api/v1/admin-role-grants", + "history": f"/api/v1/actors/{auditor.id}/admin-role-grants", + "profile": read_path(access.target.id, "profile"), + "link": read_path(access.target.id, "link"), + } + params = {"scope_type": "system", "status": "all"} if surface in {"list", "history"} else {} + response = await access.signed.client.get( + paths[surface], headers=auditor.headers, params=params + ) + assert response.status_code == 200, response.text + body = response.json() + if surface in {"permissions", "definitions"}: + assert body["total"] == len(body["items"]) == (73 if surface == "permissions" else 5) + elif surface in {"list", "history"}: + expected = {grant_id, access.bootstrap_grant_id} if surface == "list" else {grant_id} + assert body["total"] == len(expected) + assert {r["grant_id"] for r in body["items"]} == expected + assert {r["scope_project_id"] for r in body["items"]} == {None} + else: + assert body["actor_profile_id"] == str(access.target.id) + + +@pytest.mark.parametrize("scope", ["system", "project"]) +async def test_admin_grant_list_returns_exact_scope_and_count( + admin_access: AdminAccess, scope: str +) -> None: + access = admin_access + project = await create_project("Selected scope") + system = await access.signed.grant(access.admin, access.target) + auditor = await access.signed.actor("list-auditor") + audit_grant = await access.signed.grant(access.admin, auditor, role="audit_authority") + scoped = await access.signed.grant( + access.admin, access.target, role="project_manager", project_id=project + ) + params = {"scope_type": scope, "status": "all"} + if scope == "project": + params["scope_project_id"] = str(project) + response = await access.signed.client.get( + "/api/v1/admin-role-grants", + headers=access.admin.headers, + params=params, + ) + assert response.status_code == 200 + expected = {access.bootstrap_grant_id, system, audit_grant} if scope == "system" else {scoped} + assert response.json()["total"] == len(expected) + assert {r["grant_id"] for r in response.json()["items"]} == expected + assert {r["scope_project_id"] for r in response.json()["items"]} == { + None if scope == "system" else str(project) + } + + +async def test_admin_grant_history_has_bounded_payload(admin_access: AdminAccess) -> None: + access = admin_access + body = grant_body(access.target.id) + issued = await access.signed.issue(access.admin, body) + assert issued.status_code == 201 + response = await access.signed.client.get( + f"/api/v1/actors/{access.target.id}/admin-role-grants", + headers=access.admin.headers, + params={"scope_type": "system", "status": "all"}, + ) + assert response.status_code == 200 + assert response.json()["total"] == 1 + row = response.json()["items"][0] + assert row["grant_id"] == issued.json()["resource_id"] + assert row["target_actor_profile_id"] == str(access.target.id) + assert row["grant_reason"] == body["reason"] + serialized = json.dumps(response.json(), sort_keys=True) + assert access.target.subject not in serialized + assert access.target.token not in serialized + + +async def test_admin_grant_first_page_has_bounded_cursor(admin_access: AdminAccess) -> None: + access = admin_access + grant_id = await access.signed.grant(access.admin, access.target) + params = {"scope_type": "system", "status": "all", "limit": 1} + first = await access.signed.client.get( + "/api/v1/admin-role-grants", + headers=access.admin.headers, + params=params, + ) + assert first.status_code == 200 + assert first.json()["total"] == 2 + assert [r["grant_id"] for r in first.json()["items"]] == [access.bootstrap_grant_id] + cursor = first.json()["next_cursor"] + assert isinstance(cursor, str) and cursor + second = await access.signed.client.get( + "/api/v1/admin-role-grants", + headers=access.admin.headers, + params=params | {"cursor": cursor}, + ) + assert second.status_code == 200 + assert [r["grant_id"] for r in second.json()["items"]] == [grant_id] + assert second.json()["next_cursor"] is None + + +async def test_admin_grant_rejects_malformed_derivative_cursor(admin_access: AdminAccess) -> None: + access = admin_access + await access.signed.grant(access.admin, access.target) + first = await access.signed.client.get( + "/api/v1/admin-role-grants", + headers=access.admin.headers, + params={"scope_type": "system", "status": "all", "limit": 1}, + ) + assert first.status_code == 200 + cursor = first.json()["next_cursor"] + assert isinstance(cursor, str) and cursor + before = await authority_snapshot() + response = await access.signed.client.get( + "/api/v1/admin-role-grants", + headers=access.admin.headers, + params={"scope_type": "system", "cursor": cursor + "$"}, + ) + assert response.status_code == 400 + assert response.json()["error"]["code"] == "invalid_request" + assert await authority_snapshot() == before diff --git a/backend/tests/authorization/admin_access/test_grant_validation_postgresql.py b/backend/tests/authorization/admin_access/test_grant_validation_postgresql.py new file mode 100644 index 000000000..1f928810f --- /dev/null +++ b/backend/tests/authorization/admin_access/test_grant_validation_postgresql.py @@ -0,0 +1,86 @@ +"""Each original malformed selector reaches the real API validation boundary.""" + +from uuid import uuid4 + +import pytest + +from tests.authorization.admin_access.support import AdminAccess, authority_snapshot, grant_body + + +@pytest.mark.parametrize( + "case,status,code", + [ + ("pending_status", 422, "invalid_request"), + ("zero_limit", 422, "invalid_request"), + ("excessive_limit", 422, "invalid_request"), + ("malformed_actor", 422, "invalid_request"), + ("unknown_role", 422, "invalid_request"), + ("unknown_scope", 422, "invalid_request"), + ("malformed_grant", 422, "invalid_request"), + ("operator_project", 422, "invalid_role_scope"), + ("oversized_utf8_reason", 422, "invalid_request"), + ("absent_project", 404, "resource_not_found"), + ("system_with_project", 400, "invalid_request"), + ("missing_project", 400, "invalid_request"), + ("invalid_cursor", 400, "invalid_request"), + ], +) +async def test_invalid_admin_request_is_bounded( + admin_access: AdminAccess, + case: str, + status: int, + code: str, +) -> None: + access = admin_access + path = "/api/v1/admin-role-grants" + params = {"scope_type": "system"} + body = grant_body(access.target.id) + method = "get" + if case in {"pending_status", "zero_limit", "excessive_limit"}: + params |= { + "pending_status": {"status": "pending"}, + "zero_limit": {"limit": 0}, + "excessive_limit": {"limit": 101}, + }[case] + elif case == "malformed_actor": + path = "/api/v1/actors/not-a-uuid/admin-role-grants" + elif case == "system_with_project": + params["scope_project_id"] = str(uuid4()) + elif case == "missing_project": + params["scope_type"] = "project" + elif case == "invalid_cursor": + params["cursor"] = "not-a-cursor" + else: + method = "post" + if case == "malformed_grant": + path, body = ( + "/api/v1/admin-role-grants/not-a-uuid/revoke", + {"reason": "Invalid selector"}, + ) + elif case == "unknown_role": + body["role"] = "administrator" + elif case == "unknown_scope": + body |= {"role": "project_manager", "scope_type": "organization"} + elif case == "oversized_utf8_reason": + body["reason"] = "é" * 251 + else: + assert case in {"operator_project", "absent_project"} + body |= { + "role": "operator" if case == "operator_project" else "project_manager", + "scope_type": "project", + "scope_project_id": str(uuid4()), + } + before = await authority_snapshot() + if method == "get": + response = await access.signed.client.get(path, headers=access.admin.headers, params=params) + else: + response = await access.signed.client.post( + path, + headers=access.admin.headers | {"Idempotency-Key": str(uuid4())}, + json=body, + ) + assert response.status_code == status, response.text + assert response.json()["error"]["code"] == code + after = await authority_snapshot() + assert after["admin_role_grants"] == before["admin_role_grants"] + assert after["authority_idempotency_records"] == before["authority_idempotency_records"] diff --git a/backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py b/backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py new file mode 100644 index 000000000..94278610d --- /dev/null +++ b/backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py @@ -0,0 +1,54 @@ +"""Each fresh caller's disclosure serializes with its disabling transition.""" + +import pytest + +from tests.authorization.admin_access.concurrency_support import read_against_transition +from tests.authorization.admin_access.read_support import READ_ACTIONS, read_path +from tests.authorization.admin_access.support import ( + AdminAccess, + actor_observation, + authority_events, +) + + +@pytest.mark.parametrize("surface", ["profile", "link"]) +@pytest.mark.parametrize( + "transition", ["suspended", "deactivated", "link_revoked", "grant_revoked"] +) +async def test_admin_read_blocks_exact_authority_transition( + admin_access: AdminAccess, + auth_database_env: str, + monkeypatch: pytest.MonkeyPatch, + surface: str, + transition: str, +) -> None: + access = admin_access + reader = await access.signed.actor("disclosure-reader") + grant_id = await access.signed.grant(access.admin, reader, role="access_administrator") + response, changed, custody = await read_against_transition( + access, + reader, + grant_id, + surface, + transition, + database_url=auth_database_env, + monkeypatch=monkeypatch, + ) + assert custody.observed + assert response.status_code == 200, response.text + assert response.json()["actor_profile_id"] == str(access.target.id) + if transition == "grant_revoked": + assert changed.status_code == 200, changed.text + observed = await actor_observation(reader.id) + action, _ = READ_ACTIONS[surface] + events = await authority_events(action=action, event_type="SensitiveAuthorizationAllowed") + assert len(events) == 1 + assert events[0].actor_ref == str(reader.id) + assert events[0].matched_grant_id == grant_id + denied = await access.signed.client.get( + read_path(access.target.id, surface), headers=reader.headers + ) + assert denied.status_code == 403 + assert await actor_observation(reader.id) == observed + after_events = await authority_events(action=action, event_type="SensitiveAuthorizationAllowed") + assert [e.id for e in after_events] == [e.id for e in events] diff --git a/backend/tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py b/backend/tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py new file mode 100644 index 000000000..5d9dd5cfc --- /dev/null +++ b/backend/tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py @@ -0,0 +1,94 @@ +"""A delayed real observation cannot overwrite a newer committed observation.""" + +import asyncio +from uuid import uuid4 + +import pytest +from sqlalchemy.ext.asyncio import AsyncSession + +from app.modules.actors.repository import ActorRepository +from tests.authorization.admin_access.support import ( + ActorObservation, + AdminAccess, + actor_observation, + authority_events, + seed_old_observation, +) + + +async def test_older_read_cannot_regress_committed_observation( + admin_access: AdminAccess, + monkeypatch: pytest.MonkeyPatch, +) -> None: + access = admin_access + before = await seed_old_observation(access.admin.id) + older_entered, newer_committed = asyncio.Event(), asyncio.Event() + identity = f"observations-{uuid4().hex}" + newer_values: ActorObservation | None = None + touch = ActorRepository.touch_verified_actor + commit = AsyncSession.commit + failures: list[Exception] = [] + tasks: list[asyncio.Task] = [] + + async def delayed_touch(repository, profile, link): + task = asyncio.current_task() + if task is not None and task.get_name() == identity + "-older": + older_entered.set() + await newer_committed.wait() + return await touch(repository, profile, link) + + async def observed_commit(session): + nonlocal newer_values + await commit(session) + task = asyncio.current_task() + if task is not None and task.get_name() == identity + "-newer": + try: + newer_values = await actor_observation(access.admin.id) + newer_committed.set() + except Exception as exc: + failures.append(exc) + raise + + async def request_after_older_enters(): + await older_entered.wait() + return await access.signed.client.get( + "/api/v1/authorization/permissions", + headers=access.admin.headers, + ) + + with monkeypatch.context() as patch: + patch.setattr(ActorRepository, "touch_verified_actor", delayed_touch) + patch.setattr(AsyncSession, "commit", observed_commit) + try: + tasks = [ + asyncio.create_task( + access.signed.client.get( + "/api/v1/authorization/permissions", + headers=access.admin.headers, + ), + name=identity + "-older", + ), + asyncio.create_task(request_after_older_enters(), name=identity + "-newer"), + ] + responses = await asyncio.wait_for(asyncio.gather(*tasks), timeout=60) + finally: + for task in tasks: + if not task.done(): + task.cancel() + await asyncio.gather(*tasks, return_exceptions=True) + if failures: + raise AssertionError( + "newer committed observation could not be captured" + ) from failures[0] + assert [r.status_code for r in responses] == [200, 200] + assert newer_values is not None + after = await actor_observation(access.admin.id) + assert after.last_seen_at > before.last_seen_at + assert after.last_verified_at > before.last_verified_at + assert after.last_seen_at >= newer_values.last_seen_at + assert after.last_verified_at >= newer_values.last_verified_at + events = await authority_events( + action="authorization.permission_catalogue.read", + event_type="SensitiveAuthorizationAllowed", + ) + assert len(events) == 2 diff --git a/backend/tests/test_auth.py b/backend/tests/test_auth.py index 0a630b969..c3ba9dbe6 100644 --- a/backend/tests/test_auth.py +++ b/backend/tests/test_auth.py @@ -16,7 +16,7 @@ import asyncio import json import logging -from datetime import UTC, datetime +from datetime import datetime from functools import partial from pathlib import Path from typing import Any @@ -48,7 +48,6 @@ from app.modules.audit.service import AuditService from app.modules.actors.service import ActorService from app.modules.actors.models import ActorIdentityLink, ActorProfile -from app.modules.actors.repository import ActorRepository from app.modules.actors.api import ServiceIdentity from app.modules.authorization.models import ( AdminRoleGrant, @@ -65,7 +64,6 @@ ServiceActorProvisioningService, ServiceActorProvisioningUnavailable, ) -from project_create_fixtures import seed_historical_project from auth_concurrency_support import ordered_control_requests, wait_for_named_database_lock from app.modules.tasks.models import AuditEvent from scripts.bootstrap_access_administrator import ( @@ -310,1828 +308,6 @@ async def test_signed_flow_token_authorizes_actor_self_read_and_update( assert token not in serialized -async def test_signed_tokens_bootstrap_and_admin_grant_lifecycle( - auth_database_env: str, - rsa_signing_material: tuple[rsa.RSAPrivateKey, dict[str, Any]], - monkeypatch: pytest.MonkeyPatch, - caplog: pytest.LogCaptureFixture, -) -> None: - """Prove the supported bootstrap, grant, replay, scope, and revoke flow.""" - private_key, jwk = rsa_signing_material - settings = production_verifier_settings(database_url=auth_database_env) - app = create_app(settings) - app.state.auth_verifier = FlowAuthVerifier( - settings, - jwks_transport=jwks_transport(jwk), - ) - admin_token = issue_asymmetric_token( - private_key, - claims={"sub": "auth08-admin", "jti": "auth08-admin-token", "roles": ["viewer"]}, - ) - target_token = issue_asymmetric_token( - private_key, - claims={"sub": "auth08-target", "jti": "auth08-target-token", "roles": ["admin"]}, - ) - audit_token = issue_asymmetric_token( - private_key, - claims={"sub": "auth08-audit", "jti": "auth08-audit-token"}, - ) - admin_headers = {"Authorization": f"Bearer {admin_token}"} - target_headers = {"Authorization": f"Bearer {target_token}"} - audit_headers = {"Authorization": f"Bearer {audit_token}"} - original_commit = AsyncSession.commit - fail_feature_commit = False - fail_evidence_action: ActionId | None = None - fail_target_lookup: str | None = None - fail_touch = False - original_add_authority_event = AuditService.add_authority_event - original_profile_read = ActorService.read_admin_profile - original_link_read = ActorService.read_admin_identity_link - original_touch = ActorService.touch_after_authorization - - async def add_authority_event_with_failure(service, value): - nonlocal fail_evidence_action - if fail_evidence_action is not None and value.action_id is fail_evidence_action: - fail_evidence_action = None - raise SQLAlchemyError("forced authorization evidence failure") - return await original_add_authority_event(service, value) - - async def profile_read_with_failure(service, actor_profile_id): - nonlocal fail_target_lookup - if fail_target_lookup == "profile": - fail_target_lookup = None - raise SQLAlchemyError("forced profile lookup failure") - return await original_profile_read(service, actor_profile_id) - - async def link_read_with_failure(service, actor_profile_id): - nonlocal fail_target_lookup - if fail_target_lookup == "identity_link": - fail_target_lookup = None - raise SQLAlchemyError("forced identity-link lookup failure") - return await original_link_read(service, actor_profile_id) - - async def touch_with_failure(service, resolved): - nonlocal fail_touch - if fail_touch: - fail_touch = False - raise SQLAlchemyError("forced caller timestamp touch failure") - return await original_touch(service, resolved) - - async def commit_with_one_feature_failure(session: AsyncSession) -> None: - nonlocal fail_feature_commit - feature_rows = tuple(session.sync_session.new) + tuple( - session.sync_session.identity_map.values() - ) - if fail_feature_commit and any( - isinstance( - row, - (ActorProfile, ActorIdentityLink, AdminRoleGrant, AuthorityIdempotencyRecord), - ) - for row in feature_rows - ): - fail_feature_commit = False - raise SQLAlchemyError("forced feature commit failure") - await original_commit(session) - - monkeypatch.setattr(AsyncSession, "commit", commit_with_one_feature_failure) - monkeypatch.setattr(AuditService, "add_authority_event", add_authority_event_with_failure) - monkeypatch.setattr(ActorService, "read_admin_profile", profile_read_with_failure) - monkeypatch.setattr(ActorService, "read_admin_identity_link", link_read_with_failure) - monkeypatch.setattr(ActorService, "touch_after_authorization", touch_with_failure) - - async def actor_state(actor_id: UUID) -> tuple: - async with db_session.get_session_factory()() as session: - return tuple( - ( - await session.execute( - text( - "select p.display_name,p.last_seen_at,l.last_verified_at " - "from actor_profiles p join actor_identity_links l " - "on l.actor_profile_id=p.id where p.id=:actor" - ), - {"actor": str(actor_id)}, - ) - ).one() - ) - - async def authority_counts() -> tuple[int, int, int]: - async with db_session.get_session_factory()() as session: - return ( - int(await session.scalar(select(func.count()).select_from(AdminRoleGrant)) or 0), - int( - await session.scalar( - select(func.count()).select_from(AuthorityIdempotencyRecord) - ) - or 0 - ), - int(await session.scalar(select(func.count()).select_from(AuditEvent)) or 0), - ) - - def assert_retryable_service_unavailable(response: Response) -> None: - assert response.status_code == 503 - error = response.json()["error"] - assert set(error) == {"code", "message", "retryable", "correlation_id", "details"} - assert error["code"] == "service_unavailable" - assert error["message"] == "Service unavailable" - assert error["retryable"] is True - assert error["details"] == {} - UUID(error["correlation_id"]) - - async with AsyncClient( - transport=ASGITransport(app=app), - base_url="http://testserver", - ) as client: - admin_profile = await client.get("/api/v1/actors/me", headers=admin_headers) - target_profile = await client.get("/api/v1/actors/me", headers=target_headers) - audit_profile = await client.get("/api/v1/actors/me", headers=audit_headers) - assert admin_profile.status_code == target_profile.status_code == 200 - assert audit_profile.status_code == 200 - admin_id = UUID(admin_profile.json()["actor_profile_id"]) - target_id = UUID(target_profile.json()["actor_profile_id"]) - audit_id = UUID(audit_profile.json()["actor_profile_id"]) - - token_role_denied = await client.get( - "/api/v1/authorization/permissions", - headers=admin_headers, - ) - assert token_role_denied.status_code == 403 - assert token_role_denied.json()["error"]["code"] == "permission_not_granted" - - dry_run_code, dry_run = await run_admin_bootstrap(admin_id, execute=False) - assert dry_run_code == 0 - assert dry_run == { - "result_code": "eligible", - "actor_profile_id": str(admin_id), - "would_change": True, - } - - exit_code, bootstrap = await run_admin_bootstrap(admin_id, execute=True) - assert exit_code == 0 - assert bootstrap == { - "result_code": "bootstrapped", - "actor_profile_id": str(admin_id), - "grant_id": bootstrap["grant_id"], - "changed": True, - } - repeated_code, repeated = await run_admin_bootstrap(target_id, execute=True) - assert repeated_code == 3 - assert repeated == { - "result_code": "admin_role_grant_exists", - "actor_profile_id": str(target_id), - "grant_id": bootstrap["grant_id"], - "changed": False, - } - concealed_targets = { - "service": uuid4(), - "suspended": uuid4(), - "no_active_link": uuid4(), - } - private_provenance = { - "created_by": f"auth09c-created-by-{uuid4()}", - "linked_by": f"auth09c-linked-by-{uuid4()}", - "lifecycle_by": f"auth09c-lifecycle-by-{uuid4()}", - } - project_one, project_two = uuid4(), uuid4() - now = datetime.now(UTC) - async with db_session.get_session_factory()() as session: - target_row = await session.get(ActorProfile, str(target_id)) - assert target_row is not None - target_row.contact_email = "auth09c-private-contact@example.test" - await seed_historical_project( - session, - project_id=str(project_one), - name="AUTH-08 scope one", - slug=f"auth08-scope-one-{project_one}", - ) - await seed_historical_project( - session, - project_id=str(project_two), - name="AUTH-08 scope two", - slug=f"auth08-scope-two-{project_two}", - ) - session.add_all( - [ - ActorProfile( - id=str(concealed_targets["service"]), - actor_kind="service", - status="active", - provisioning_method="manual_service_provisioning", - service_identity="workstream.artifact.verifier", - created_by=private_provenance["created_by"], - ), - ActorProfile( - id=str(concealed_targets["suspended"]), - actor_kind="human", - status="suspended", - provisioning_method="automatic_first_access", - created_by=private_provenance["created_by"], - suspended_by=private_provenance["lifecycle_by"], - suspended_at=now, - suspension_reason="Concealment fixture", - ), - ActorProfile( - id=str(concealed_targets["no_active_link"]), - actor_kind="human", - status="active", - provisioning_method="automatic_first_access", - created_by=private_provenance["created_by"], - ), - ] - ) - await session.flush() - session.add_all( - [ - ActorIdentityLink( - id=str(uuid4()), - actor_profile_id=str(concealed_targets["service"]), - issuer="https://identity.test", - subject="auth08-service-target", - subject_kind="service", - status="active", - linked_by=private_provenance["linked_by"], - ), - ActorIdentityLink( - id=str(uuid4()), - actor_profile_id=str(concealed_targets["suspended"]), - issuer="https://identity.test", - subject="auth08-suspended-target", - subject_kind="human", - status="active", - linked_by=private_provenance["linked_by"], - last_verified_at=now, - ), - ActorIdentityLink( - id=str(uuid4()), - actor_profile_id=str(concealed_targets["no_active_link"]), - issuer="https://identity.test", - subject="auth08-revoked-link-target", - subject_kind="human", - status="revoked", - linked_by=private_provenance["linked_by"], - last_verified_at=now, - revoked_by=private_provenance["lifecycle_by"], - revoked_at=now, - revoked_reason="Concealment fixture", - ), - ] - ) - await session.commit() - - profile_fields = { - "actor_profile_id", - "actor_kind", - "status", - "provisioning_method", - "service_identity", - "display_name", - "created_at", - "updated_at", - "last_seen_at", - "suspended_at", - "reactivated_at", - "deactivated_at", - } - link_fields = { - "identity_link_id", - "actor_profile_id", - "subject_kind", - "status", - "linked_at", - "last_verified_at", - "revoked_at", - "reactivated_at", - } - caplog.clear() - caplog.set_level(logging.DEBUG, logger="app") - before_admin_actor_read = await actor_state(admin_id) - before_target_actor_read = await actor_state(target_id) - target_admin_profile = await client.get( - f"/api/v1/actors/{target_id}", - headers=admin_headers, - ) - target_admin_link = await client.get( - f"/api/v1/actors/{target_id}/identity-links", - headers=admin_headers, - ) - service_admin_profile = await client.get( - f"/api/v1/actors/{concealed_targets['service']}", - headers=admin_headers, - ) - service_admin_link = await client.get( - f"/api/v1/actors/{concealed_targets['service']}/identity-links", - headers=admin_headers, - ) - suspended_admin_profile = await client.get( - f"/api/v1/actors/{concealed_targets['suspended']}", - headers=admin_headers, - ) - revoked_admin_link = await client.get( - f"/api/v1/actors/{concealed_targets['no_active_link']}/identity-links", - headers=admin_headers, - ) - assert [ - response.status_code - for response in ( - target_admin_profile, - target_admin_link, - service_admin_profile, - service_admin_link, - suspended_admin_profile, - revoked_admin_link, - ) - ] == [200] * 6 - assert set(target_admin_profile.json()) == profile_fields - assert set(target_admin_link.json()) == link_fields - assert target_admin_profile.json()["actor_kind"] == "human" - assert target_admin_profile.json()["service_identity"] is None - assert service_admin_profile.json()["actor_kind"] == "service" - assert service_admin_profile.json()["service_identity"] == ( - ServiceIdentity.ARTIFACT_VERIFIER.value - ) - assert service_admin_profile.json()["last_seen_at"] is None - assert service_admin_link.json()["last_verified_at"] is None - assert suspended_admin_profile.json()["status"] == "suspended" - assert revoked_admin_link.json()["status"] == "revoked" - serialized_admin_reads = json.dumps( - [ - target_admin_profile.json(), - target_admin_link.json(), - service_admin_profile.json(), - service_admin_link.json(), - suspended_admin_profile.json(), - revoked_admin_link.json(), - ], - sort_keys=True, - ) - for private_value in ( - "auth08-target", - "auth08-service-target", - "auth08-suspended-target", - "auth08-revoked-link-target", - "https://identity.test", - "Concealment fixture", - "auth09c-private-contact@example.test", - admin_token, - target_token, - bootstrap["grant_id"], - *private_provenance.values(), - ): - assert private_value not in serialized_admin_reads - assert private_value not in caplog.text - assert await actor_state(target_id) == before_target_actor_read - after_admin_actor_read = await actor_state(admin_id) - assert after_admin_actor_read[1] > before_admin_actor_read[1] - assert after_admin_actor_read[2] > before_admin_actor_read[2] - - async with db_session.get_session_factory()() as session: - target_allow_events = ( - await session.scalars( - select(AuditEvent).where( - AuditEvent.event_type == "SensitiveAuthorizationAllowed", - AuditEvent.action_id.in_( - ("actor.profile.read", "actor.identity_link.read") - ), - AuditEvent.resource_id == str(target_id), - ) - ) - ).all() - assert len(target_allow_events) == 2 - expected_evidence = { - "actor.profile.read": ("actor.profile.read_any", target_admin_profile), - "actor.identity_link.read": ("actor.identity_link.read", target_admin_link), - } - assert {event.action_id for event in target_allow_events} == set(expected_evidence) - for event in target_allow_events: - expected_permission, route_response = expected_evidence[event.action_id] - assert event.permission_id == expected_permission - assert event.actor_id == str(admin_id) - assert event.target_actor_ref == str(target_id) - assert event.target_ref_id == str(target_id) - assert event.matched_grant_id == bootstrap["grant_id"] - assert event.project_id is None - assert event.after_facts == {"allowed": True} - assert UUID(str(event.request_id)) == UUID(route_response.headers["x-request-id"]) - assert UUID(str(event.correlation_id)) == UUID( - route_response.headers["x-correlation-id"] - ) - - async def actor_admin_state() -> tuple[datetime, datetime, datetime]: - async with db_session.get_session_factory()() as session: - return tuple( - ( - await session.execute( - text( - "select p.updated_at,p.last_seen_at,l.last_verified_at " - "from actor_profiles p join actor_identity_links l " - "on l.actor_profile_id=p.id where p.id=:actor" - ), - {"actor": str(admin_id)}, - ) - ).one() - ) - - before_self_profile = await actor_admin_state() - before_self_profile_counts = await authority_counts() - self_profile = await client.get( - f"/api/v1/actors/{admin_id}", - headers=admin_headers, - ) - assert self_profile.status_code == 200, self_profile.text - after_self_profile = await actor_admin_state() - assert after_self_profile[0] > before_self_profile[0] - assert after_self_profile[1] > before_self_profile[1] - assert after_self_profile[2] > before_self_profile[2] - assert datetime.fromisoformat(self_profile.json()["updated_at"]) == after_self_profile[0] - assert datetime.fromisoformat(self_profile.json()["last_seen_at"]) == after_self_profile[1] - after_self_profile_counts = await authority_counts() - assert after_self_profile_counts[:2] == before_self_profile_counts[:2] - assert after_self_profile_counts[2] == before_self_profile_counts[2] + 1 - - before_self_link = await actor_admin_state() - before_self_link_counts = await authority_counts() - self_link = await client.get( - f"/api/v1/actors/{admin_id}/identity-links", - headers=admin_headers, - ) - assert self_link.status_code == 200, self_link.text - after_self_link = await actor_admin_state() - assert after_self_link[0] > before_self_link[0] - assert after_self_link[1] > before_self_link[1] - assert after_self_link[2] > before_self_link[2] - assert datetime.fromisoformat(self_link.json()["last_verified_at"]) == after_self_link[2] - after_self_link_counts = await authority_counts() - assert after_self_link_counts[:2] == before_self_link_counts[:2] - assert after_self_link_counts[2] == before_self_link_counts[2] + 1 - - before_missing_reads = await actor_state(admin_id) - before_missing_authority_counts = await authority_counts() - absent_id = uuid4() - missing_profile = await client.get( - f"/api/v1/actors/{absent_id}", - headers=admin_headers, - ) - missing_link = await client.get( - f"/api/v1/actors/{absent_id}/identity-links", - headers=admin_headers, - ) - assert missing_profile.status_code == missing_link.status_code == 404 - concealed_missing_bodies = [] - for response in (missing_profile, missing_link): - body = response.json() - UUID(body["error"].pop("correlation_id")) - concealed_missing_bodies.append(body) - assert concealed_missing_bodies[0] == concealed_missing_bodies[1] - assert concealed_missing_bodies[0]["error"]["code"] == "actor_resource_not_found" - assert await actor_state(admin_id) == before_missing_reads - assert await authority_counts() == before_missing_authority_counts - - async def assert_failed_admin_read(path: str) -> None: - before_failure_state = await actor_state(admin_id) - before_failure_counts = await authority_counts() - failed_response = await client.get(path, headers=admin_headers) - assert_retryable_service_unavailable(failed_response) - assert await actor_state(admin_id) == before_failure_state - assert await authority_counts() == before_failure_counts - - profile_path = f"/api/v1/actors/{target_id}" - link_path = f"/api/v1/actors/{target_id}/identity-links" - for action_id, path in ( - (ActionId.ACTOR_PROFILE_READ, profile_path), - (ActionId.ACTOR_IDENTITY_LINK_READ, link_path), - ): - fail_evidence_action = action_id - await assert_failed_admin_read(path) - - for lookup_kind, path in ( - ("profile", profile_path), - ("identity_link", link_path), - ): - fail_target_lookup = lookup_kind - await assert_failed_admin_read(path) - - for path in (profile_path, link_path): - fail_touch = True - await assert_failed_admin_read(path) - - for path in (profile_path, link_path): - fail_feature_commit = True - await assert_failed_admin_read(path) - - before_read = await actor_state(admin_id) - fail_feature_commit = True - failed_read = await client.get( - "/api/v1/authorization/permissions", - headers=admin_headers, - ) - assert_retryable_service_unavailable(failed_read) - assert await actor_state(admin_id) == before_read - - permissions = await client.get( - "/api/v1/authorization/permissions", - headers=admin_headers, - ) - definitions = await client.get( - "/api/v1/authorization/admin-role-definitions", - headers=admin_headers, - ) - assert permissions.status_code == definitions.status_code == 200 - assert (permissions.json()["total"], len(permissions.json()["items"])) == (73, 73) - assert definitions.json()["total"] == 5 - assert [item["role"] for item in definitions.json()["items"]] == [ - "access_administrator", - "operator", - "project_manager", - "finance_authority", - "audit_authority", - ] - after_read = await actor_state(admin_id) - assert after_read[1] > before_read[1] - assert after_read[2] > before_read[2] - - fail_feature_commit = True - failed_patch = await client.patch( - "/api/v1/actors/me", - headers=admin_headers, - json={"display_name": "AUTH-08 administrator"}, - ) - assert_retryable_service_unavailable(failed_patch) - assert await actor_state(admin_id) == after_read - successful_patch = await client.patch( - "/api/v1/actors/me", - headers=admin_headers, - json={"display_name": "AUTH-08 administrator"}, - ) - assert successful_patch.status_code == 200 - after_patch = await actor_state(admin_id) - assert after_patch[0] == "AUTH-08 administrator" - assert after_patch[1] > after_read[1] - assert after_patch[2] > after_read[2] - - self_grant = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(admin_id), - "role": "operator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Must be rejected", - }, - ) - invalid_role_scope = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(target_id), - "role": "operator", - "scope_type": "project", - "scope_project_id": str(uuid4()), - "reason": "Invalid role scope", - }, - ) - oversized_reason = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(target_id), - "role": "operator", - "scope_type": "system", - "scope_project_id": None, - "reason": "\u00e9" * 251, - }, - ) - missing_target = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(uuid4()), - "role": "operator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Absent target", - }, - ) - assert self_grant.status_code == 403 - assert self_grant.json()["error"]["code"] == "self_grant_forbidden" - assert invalid_role_scope.status_code == 422 - assert invalid_role_scope.json()["error"]["code"] == "invalid_role_scope" - assert oversized_reason.status_code == 422 - assert oversized_reason.json()["error"]["code"] == "invalid_request" - assert missing_target.status_code == 404 - assert missing_target.json()["error"]["code"] == "actor_not_found" - concealed_responses = [missing_target] - for target in concealed_targets.values(): - concealed_responses.append( - await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(target), - "role": "operator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Concealed ineligible target", - }, - ) - ) - assert [response.status_code for response in concealed_responses] == [404] * 4 - assert { - ( - response.json()["detail"], - response.json()["error"]["code"], - response.json()["error"]["message"], - response.json()["error"]["retryable"], - ) - for response in concealed_responses - } == {("Actor not found", "actor_not_found", "Actor not found", False)} - async with db_session.get_session_factory()() as session: - await session.execute(text("alter table actor_profiles disable trigger user")) - await session.execute(text("alter table actor_identity_links disable trigger user")) - await session.execute( - text( - "update actor_profiles set status='active',suspended_by=null," - "suspended_at=null,suspension_reason=null,reactivated_by=null," - "reactivated_at=null,reactivation_reason=null where id=:actor" - ), - {"actor": str(concealed_targets["suspended"])}, - ) - await session.execute( - text( - "update actor_identity_links set status='active',revoked_by=null," - "revoked_at=null,revoked_reason=null,reactivated_by=null," - "reactivated_at=null,reactivation_reason=null " - "where actor_profile_id=:actor" - ), - {"actor": str(concealed_targets["no_active_link"])}, - ) - await session.execute(text("alter table actor_identity_links enable trigger user")) - await session.execute(text("alter table actor_profiles enable trigger user")) - await session.commit() - - malformed_responses = [ - await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "status": "pending"}, - ), - await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "limit": 0}, - ), - await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "limit": 101}, - ), - await client.get( - "/api/v1/actors/not-a-uuid/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system"}, - ), - await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(target_id), - "role": "administrator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Unknown role", - }, - ), - await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(target_id), - "role": "project_manager", - "scope_type": "organization", - "scope_project_id": None, - "reason": "Unknown scope", - }, - ), - await client.post( - "/api/v1/admin-role-grants/not-a-uuid/revoke", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={"reason": "Malformed grant selector"}, - ), - ] - assert [response.status_code for response in malformed_responses] == [422] * 7 - assert {response.json()["error"]["code"] for response in malformed_responses} == { - "invalid_request" - } - - absent_project = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(target_id), - "role": "project_manager", - "scope_type": "project", - "scope_project_id": str(uuid4()), - "reason": "Absent canonical project", - }, - ) - assert absent_project.status_code == 404 - assert absent_project.json()["error"]["code"] == "resource_not_found" - - for actor_id, role in ( - (target_id, "project_manager"), - (audit_id, "audit_authority"), - ): - response = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(actor_id), - "role": role, - "scope_type": "project", - "scope_project_id": str(project_one), - "reason": "Exact project authority proof", - }, - ) - assert response.status_code == 201, response.text - - audit_visible = await client.get( - "/api/v1/admin-role-grants", - headers=audit_headers, - params={"scope_type": "project", "scope_project_id": str(project_one)}, - ) - project_audit_actor_read = await client.get( - f"/api/v1/actors/{target_id}", - headers=audit_headers, - ) - project_audit_link_read = await client.get( - f"/api/v1/actors/{target_id}/identity-links", - headers=audit_headers, - ) - audit_wrong_scope = await client.get( - "/api/v1/admin-role-grants", - headers=audit_headers, - params={"scope_type": "project", "scope_project_id": str(project_two)}, - ) - audit_mutation = await client.post( - "/api/v1/admin-role-grants", - headers={**audit_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(audit_id), - "role": "operator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Audit authority is read-only", - }, - ) - audit_history_visible = await client.get( - f"/api/v1/actors/{target_id}/admin-role-grants", - headers=audit_headers, - params={"scope_type": "project", "scope_project_id": str(project_one)}, - ) - assert audit_visible.status_code == 200 - assert audit_visible.json()["total"] == 2 - assert {item["scope_project_id"] for item in audit_visible.json()["items"]} == { - str(project_one) - } - assert audit_wrong_scope.status_code == audit_mutation.status_code == 403 - for project_audit_read in (project_audit_actor_read, project_audit_link_read): - assert project_audit_read.status_code == 403 - assert project_audit_read.json()["error"]["code"] == "permission_not_granted" - assert audit_wrong_scope.json()["error"]["code"] == "scope_not_authorized" - assert audit_mutation.json()["error"]["code"] == "permission_not_granted" - assert audit_history_visible.status_code == 200 - assert audit_history_visible.json()["total"] == 1 - assert audit_history_visible.json()["items"][0]["target_actor_profile_id"] == str(target_id) - - system_audit_grant = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(audit_id), - "role": "audit_authority", - "scope_type": "system", - "scope_project_id": None, - "reason": "System audit custody proof", - }, - ) - assert system_audit_grant.status_code == 201, system_audit_grant.text - system_audit_reads = [ - await client.get("/api/v1/authorization/permissions", headers=audit_headers), - await client.get( - "/api/v1/authorization/admin-role-definitions", - headers=audit_headers, - ), - await client.get( - "/api/v1/admin-role-grants", - headers=audit_headers, - params={"scope_type": "system", "status": "all"}, - ), - await client.get( - f"/api/v1/actors/{audit_id}/admin-role-grants", - headers=audit_headers, - params={"scope_type": "system", "status": "all"}, - ), - await client.get(f"/api/v1/actors/{target_id}", headers=audit_headers), - await client.get( - f"/api/v1/actors/{target_id}/identity-links", - headers=audit_headers, - ), - ] - assert [response.status_code for response in system_audit_reads] == [200] * 6 - assert system_audit_reads[0].json()["total"] == 73 - assert system_audit_reads[1].json()["total"] == 5 - assert system_audit_reads[2].json()["total"] == 2 - assert system_audit_reads[3].json()["total"] == 1 - - key = str(uuid4()) - issue_payload = { - "target_actor_profile_id": str(target_id), - "role": "operator", - "scope_type": "system", - "scope_project_id": None, - "reason": "On-call operations coverage", - } - before_failed_issue = await authority_counts() - before_failed_issue_actor = await actor_state(admin_id) - fail_feature_commit = True - failed_issue = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": key}, - json=issue_payload, - ) - assert_retryable_service_unavailable(failed_issue) - assert await authority_counts() == before_failed_issue - assert await actor_state(admin_id) == before_failed_issue_actor - issued = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": key}, - json=issue_payload, - ) - after_issue_actor = await actor_state(admin_id) - assert after_issue_actor[1] > before_failed_issue_actor[1] - assert after_issue_actor[2] > before_failed_issue_actor[2] - replayed = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": key}, - json=issue_payload, - ) - assert issued.status_code == 201, issued.text - assert replayed.status_code == 201, replayed.text - assert issued.json() == replayed.json() - grant_id = issued.json()["resource_id"] - - mismatch = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": key}, - json=issue_payload | {"reason": "Different request"}, - ) - duplicate = await client.post( - "/api/v1/admin-role-grants", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json=issue_payload, - ) - assert mismatch.status_code == 409, mismatch.text - assert mismatch.json()["error"]["code"] == "idempotency_mismatch" - assert duplicate.status_code == 409 - assert duplicate.json()["error"]["code"] == "admin_role_grant_exists" - - listed = await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "status": "all"}, - ) - history = await client.get( - f"/api/v1/actors/{target_id}/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "status": "all"}, - ) - assert listed.status_code == history.status_code == 200 - assert listed.json()["total"] == 3 - assert history.json()["total"] == 1 - assert history.json()["items"][0]["grant_reason"] == issue_payload["reason"] - serialized = json.dumps(history.json(), sort_keys=True) - assert "auth08-target" not in serialized - assert target_token not in serialized - - invalid_scope = await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "scope_project_id": str(uuid4())}, - ) - invalid_cursor = await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "cursor": "not-a-cursor"}, - ) - first_page = await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "system", "status": "all", "limit": 1}, - ) - malformed_valid_cursor = await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={ - "scope_type": "system", - "cursor": first_page.json()["next_cursor"] + "$", - }, - ) - assert invalid_scope.status_code == invalid_cursor.status_code == 400 - missing_project_scope = await client.get( - "/api/v1/admin-role-grants", - headers=admin_headers, - params={"scope_type": "project"}, - ) - assert missing_project_scope.status_code == 400 - assert missing_project_scope.json()["error"]["code"] == "invalid_request" - assert malformed_valid_cursor.status_code == 400 - assert invalid_scope.json()["error"]["code"] == "invalid_request" - assert invalid_cursor.json()["error"]["code"] == "invalid_request" - - target_self = await client.get("/api/v1/actors/me", headers=target_headers) - target_definitions = await client.get( - "/api/v1/authorization/admin-role-definitions", - headers=target_headers, - ) - assert target_self.json()["admin_roles"] == ["operator", "project_manager"] - assert target_definitions.status_code == 403 - assert target_definitions.json()["error"]["code"] == "permission_not_granted" - - revoke_key = str(uuid4()) - before_failed_revoke = await authority_counts() - before_failed_revoke_actor = await actor_state(admin_id) - fail_feature_commit = True - failed_revoke = await client.post( - f"/api/v1/admin-role-grants/{grant_id}/revoke", - headers={**admin_headers, "Idempotency-Key": revoke_key}, - json={"reason": "On-call rotation ended"}, - ) - assert_retryable_service_unavailable(failed_revoke) - assert await authority_counts() == before_failed_revoke - assert await actor_state(admin_id) == before_failed_revoke_actor - revoked = await client.post( - f"/api/v1/admin-role-grants/{grant_id}/revoke", - headers={**admin_headers, "Idempotency-Key": revoke_key}, - json={"reason": "On-call rotation ended"}, - ) - after_revoke_actor = await actor_state(admin_id) - assert after_revoke_actor[1] > before_failed_revoke_actor[1] - assert after_revoke_actor[2] > before_failed_revoke_actor[2] - revoke_replay = await client.post( - f"/api/v1/admin-role-grants/{grant_id}/revoke", - headers={**admin_headers, "Idempotency-Key": revoke_key}, - json={"reason": "On-call rotation ended"}, - ) - assert revoked.status_code == revoke_replay.status_code == 200 - assert revoked.json() == revoke_replay.json() - assert revoked.json()["version"] == 2 - - before_revoke_mismatch = await authority_counts() - revoke_mismatch = await client.post( - f"/api/v1/admin-role-grants/{grant_id}/revoke", - headers={**admin_headers, "Idempotency-Key": revoke_key}, - json={"reason": "Different revoke request"}, - ) - after_revoke_mismatch = await authority_counts() - assert revoke_mismatch.status_code == 409 - assert revoke_mismatch.json()["error"]["code"] == "idempotency_mismatch" - assert after_revoke_mismatch[:2] == before_revoke_mismatch[:2] - assert after_revoke_mismatch[2] == before_revoke_mismatch[2] + 1 - - revoked_new_key = await client.post( - f"/api/v1/admin-role-grants/{grant_id}/revoke", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={"reason": "Already revoked"}, - ) - absent_grant = await client.post( - f"/api/v1/admin-role-grants/{uuid4()}/revoke", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={"reason": "Absent grant"}, - ) - self_revoke = await client.post( - f"/api/v1/admin-role-grants/{bootstrap['grant_id']}/revoke", - headers={**admin_headers, "Idempotency-Key": str(uuid4())}, - json={"reason": "Must be rejected"}, - ) - assert revoked_new_key.status_code == absent_grant.status_code == 404 - assert revoked_new_key.json()["error"]["code"] == "grant_not_found" - concealed_grant_bodies = [] - for response in (revoked_new_key, absent_grant): - body = response.json() - UUID(body["error"].pop("correlation_id")) - concealed_grant_bodies.append(body) - assert concealed_grant_bodies[0] == concealed_grant_bodies[1] - assert self_revoke.status_code == 403 - assert self_revoke.json()["error"]["code"] == "self_role_revoke_forbidden" - - target_after = await client.get("/api/v1/actors/me", headers=target_headers) - assert target_after.json()["admin_roles"] == ["project_manager"] - async with db_session.get_session_factory()() as session: - lifecycle_counts = dict( - ( - await session.execute( - select(AuditEvent.event_type, func.count()) - .where( - AuditEvent.event_type.in_( - [ - "InitialAccessAdministratorBootstrapped", - "AdminRoleGrantIssued", - "AdminRoleGrantRevoked", - "AuthorityInvalidationRequested", - ] - ) - ) - .group_by(AuditEvent.event_type) - ) - ).all() - ) - assert lifecycle_counts == { - "InitialAccessAdministratorBootstrapped": 1, - "AdminRoleGrantIssued": 4, - "AdminRoleGrantRevoked": 1, - "AuthorityInvalidationRequested": 5, - } - await db_session.dispose_engine() - - - - - - - - - - - - -async def test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe( - auth_database_env: str, - rsa_signing_material: tuple[rsa.RSAPrivateKey, dict[str, Any]], - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Use independent request sessions and barriers to prove serialized authority.""" - private_key, jwk = rsa_signing_material - settings = production_verifier_settings(database_url=auth_database_env) - app = create_app(settings) - app.state.auth_verifier = FlowAuthVerifier(settings, jwks_transport=jwks_transport(jwk)) - tokens = { - name: issue_asymmetric_token( - private_key, - claims={"sub": f"auth08-race-{name}", "jti": f"auth08-race-{name}-token"}, - ) - for name in ( - "one", - "two", - "target", - "duplicate", - "pm-target-one", - "pm-target-two", - ) - } - headers = {name: {"Authorization": f"Bearer {token}"} for name, token in tokens.items()} - - async with AsyncClient( - transport=ASGITransport(app=app), - base_url="http://testserver", - ) as client: - profiles = { - name: UUID( - (await client.get("/api/v1/actors/me", headers=actor_headers)).json()[ - "actor_profile_id" - ] - ) - for name, actor_headers in headers.items() - } - - original_lock_control = AdminAuthorizationRepository.lock_control - bootstrap_ready = asyncio.Event() - bootstrap_arrivals = 0 - - async def barrier_lock_control(self): - nonlocal bootstrap_arrivals - bootstrap_arrivals += 1 - if bootstrap_arrivals == 2: - bootstrap_ready.set() - await bootstrap_ready.wait() - return await original_lock_control(self) - - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - barrier_lock_control, - ) - bootstrap_results = await asyncio.gather( - run_admin_bootstrap(profiles["one"], execute=True), - run_admin_bootstrap(profiles["two"], execute=True), - ) - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - original_lock_control, - ) - assert sorted(code for code, _ in bootstrap_results) == [0, 3] - winner_index = next( - index for index, (code, _result) in enumerate(bootstrap_results) if code == 0 - ) - winner_name = ("one", "two")[winner_index] - other_name = ("two", "one")[winner_index] - bootstrap_grant_id = bootstrap_results[winner_index][1]["grant_id"] - - async def read_winner_timestamps() -> tuple[datetime, datetime]: - async with db_session.get_session_factory()() as session: - return tuple( - ( - await session.execute( - text( - "select p.last_seen_at,l.last_verified_at " - "from actor_profiles p join actor_identity_links l " - "on l.actor_profile_id=p.id where p.id=:actor" - ), - {"actor": str(profiles[winner_name])}, - ) - ).one() - ) - - timestamps_before = await read_winner_timestamps() - original_touch_verified_actor = ActorRepository.touch_verified_actor - original_commit = AsyncSession.commit - older_touch_ready = asyncio.Event() - newer_committed = asyncio.Event() - newer_committed_timestamps: tuple[datetime, datetime] | None = None - - async def barrier_touch_verified_actor(self, profile, link): - if current_task_name() == "auth08-older-timestamp-read": - older_touch_ready.set() - await newer_committed.wait() - return await original_touch_verified_actor(self, profile, link) - - async def ordered_commit(session: AsyncSession) -> None: - nonlocal newer_committed_timestamps - await original_commit(session) - if current_task_name() == "auth08-newer-timestamp-read": - newer_committed_timestamps = await read_winner_timestamps() - newer_committed.set() - - monkeypatch.setattr( - ActorRepository, - "touch_verified_actor", - barrier_touch_verified_actor, - ) - monkeypatch.setattr(AsyncSession, "commit", ordered_commit) - older_read = asyncio.create_task( - client.get( - "/api/v1/authorization/permissions", - headers=headers[winner_name], - ), - name="auth08-older-timestamp-read", - ) - await older_touch_ready.wait() - newer_read = asyncio.create_task( - client.get( - "/api/v1/authorization/permissions", - headers=headers[winner_name], - ), - name="auth08-newer-timestamp-read", - ) - try: - crossed_reads = await asyncio.gather(older_read, newer_read) - finally: - monkeypatch.setattr( - ActorRepository, - "touch_verified_actor", - original_touch_verified_actor, - ) - monkeypatch.setattr(AsyncSession, "commit", original_commit) - assert [response.status_code for response in crossed_reads] == [200, 200] - assert newer_committed_timestamps is not None - timestamps_after = await read_winner_timestamps() - async with db_session.get_session_factory()() as session: - crossed_allow_count = await session.scalar( - select(func.count()) - .select_from(AuditEvent) - .where( - AuditEvent.action_id == "authorization.permission_catalogue.read", - AuditEvent.event_type == "SensitiveAuthorizationAllowed", - ) - ) - assert timestamps_after[0] > timestamps_before[0] - assert timestamps_after[1] > timestamps_before[1] - assert timestamps_after[0] >= newer_committed_timestamps[0] - assert timestamps_after[1] >= newer_committed_timestamps[1] - assert crossed_allow_count == 2 - - original_reserve = AuthorityIdempotencyRepository.reserve - reserve_ready = asyncio.Event() - reserve_arrivals = 0 - - async def barrier_reserve(self, **kwargs): - nonlocal reserve_arrivals - reserve_arrivals += 1 - if reserve_arrivals == 2: - reserve_ready.set() - await reserve_ready.wait() - return await original_reserve(self, **kwargs) - - monkeypatch.setattr(AuthorityIdempotencyRepository, "reserve", barrier_reserve) - replay_key = str(uuid4()) - operator_payload = { - "target_actor_profile_id": str(profiles["target"]), - "role": "operator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Concurrent replay proof", - } - replay_responses = await asyncio.gather( - *( - client.post( - "/api/v1/admin-role-grants", - headers={**headers[winner_name], "Idempotency-Key": replay_key}, - json=operator_payload, - ) - for _ in range(2) - ) - ) - monkeypatch.setattr(AuthorityIdempotencyRepository, "reserve", original_reserve) - assert [response.status_code for response in replay_responses] == [201, 201] - assert replay_responses[0].json() == replay_responses[1].json() - - duplicate_ready = asyncio.Event() - duplicate_arrivals = 0 - - async def duplicate_barrier_lock_control(self): - nonlocal duplicate_arrivals - duplicate_arrivals += 1 - if duplicate_arrivals == 2: - duplicate_ready.set() - await duplicate_ready.wait() - return await original_lock_control(self) - - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - duplicate_barrier_lock_control, - ) - duplicate_payload = operator_payload | { - "target_actor_profile_id": str(profiles["duplicate"]), - "reason": "Different-key duplicate proof", - } - duplicate_responses = await asyncio.gather( - *( - client.post( - "/api/v1/admin-role-grants", - headers={**headers[winner_name], "Idempotency-Key": str(uuid4())}, - json=duplicate_payload, - ) - for _ in range(2) - ) - ) - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - original_lock_control, - ) - assert sorted(response.status_code for response in duplicate_responses) == [201, 409] - assert ( - next( - response for response in duplicate_responses if response.status_code == 409 - ).json()["error"]["code"] - == "admin_role_grant_exists" - ) - - second_admin = await client.post( - "/api/v1/admin-role-grants", - headers={**headers[winner_name], "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(profiles[other_name]), - "role": "access_administrator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Cross-revocation proof", - }, - ) - assert second_admin.status_code == 201, second_admin.text - second_admin_grant_id = second_admin.json()["resource_id"] - - revoke_ready = asyncio.Event() - revoke_arrivals = 0 - - async def revoke_barrier_lock_control(self): - nonlocal revoke_arrivals - revoke_arrivals += 1 - if revoke_arrivals == 2: - revoke_ready.set() - await revoke_ready.wait() - return await original_lock_control(self) - - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - revoke_barrier_lock_control, - ) - revoke_results = await asyncio.gather( - client.post( - f"/api/v1/admin-role-grants/{second_admin_grant_id}/revoke", - headers={**headers[winner_name], "Idempotency-Key": str(uuid4())}, - json={"reason": "Concurrent cross-revoke"}, - ), - client.post( - f"/api/v1/admin-role-grants/{bootstrap_grant_id}/revoke", - headers={**headers[other_name], "Idempotency-Key": str(uuid4())}, - json={"reason": "Concurrent cross-revoke"}, - ), - ) - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - original_lock_control, - ) - assert sorted(response.status_code for response in revoke_results) == [200, 403] - assert ( - next(response for response in revoke_results if response.status_code == 403).json()[ - "error" - ]["code"] - == "permission_not_granted" - ) - - if revoke_results[0].status_code == 200: - surviving_admin, issuance_actor = winner_name, other_name - else: - surviving_admin, issuance_actor = other_name, winner_name - - async def restore_issuance_actor() -> str: - response = await client.post( - "/api/v1/admin-role-grants", - headers={ - **headers[surviving_admin], - "Idempotency-Key": str(uuid4()), - }, - json={ - "target_actor_profile_id": str(profiles[issuance_actor]), - "role": "access_administrator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Ordered revoke-versus-issue proof", - }, - ) - assert response.status_code == 201, response.text - return response.json()["resource_id"] - - async def run_ordered_revoke_vs_issue( - *, - first: str, - target_name: str, - issuance_grant_id: str, - ) -> tuple[Response, Response]: - first_locked = asyncio.Event() - - async def ordered_lock_control(self): - if current_task_name() == first: - control = await original_lock_control(self) - first_locked.set() - return control - await first_locked.wait() - return await original_lock_control(self) - - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - ordered_lock_control, - ) - issue_task = asyncio.create_task( - client.post( - "/api/v1/admin-role-grants", - headers={ - **headers[issuance_actor], - "Idempotency-Key": str(uuid4()), - }, - json={ - "target_actor_profile_id": str(profiles[target_name]), - "role": "project_manager", - "scope_type": "system", - "scope_project_id": None, - "reason": "Concurrent Project Manager authorization proof", - }, - ), - name="issue", - ) - revoke_task = asyncio.create_task( - client.post( - f"/api/v1/admin-role-grants/{issuance_grant_id}/revoke", - headers={ - **headers[surviving_admin], - "Idempotency-Key": str(uuid4()), - }, - json={"reason": "Concurrent authority removal proof"}, - ), - name="revoke", - ) - issue_response, revoke_response = await asyncio.gather( - issue_task, - revoke_task, - ) - monkeypatch.setattr( - AdminAuthorizationRepository, - "lock_control", - original_lock_control, - ) - return issue_response, revoke_response - - issuance_grant_id = await restore_issuance_actor() - issue_first, revoke_second = await run_ordered_revoke_vs_issue( - first="issue", - target_name="pm-target-one", - issuance_grant_id=issuance_grant_id, - ) - assert issue_first.status_code == 201, issue_first.text - assert revoke_second.status_code == 200, revoke_second.text - issue_first_grant_id = issue_first.json()["resource_id"] - revoke_second_grant_id = issuance_grant_id - - issuance_grant_id = await restore_issuance_actor() - revoke_first_grant_id = issuance_grant_id - issue_second, revoke_first = await run_ordered_revoke_vs_issue( - first="revoke", - target_name="pm-target-two", - issuance_grant_id=issuance_grant_id, - ) - assert revoke_first.status_code == 200, revoke_first.text - assert issue_second.status_code == 403 - assert issue_second.json()["error"]["code"] == "permission_not_granted" - - async with db_session.get_session_factory()() as session: - active_admins = await session.scalar( - text( - "select count(*) from admin_role_grants where " - "role='access_administrator' and scope_type='system' and status='active'" - ) - ) - event_counts = dict( - ( - await session.execute( - select(AuditEvent.event_type, func.count()) - .where( - AuditEvent.event_type.in_( - [ - "InitialAccessAdministratorBootstrapped", - "AdminRoleGrantIssued", - "AdminRoleGrantRevoked", - "AdminRoleGrantIssueDenied", - ] - ) - ) - .group_by(AuditEvent.event_type) - ) - ).all() - ) - linked_pair_counts: dict[tuple[str, str], int] = {} - for resource_id, event_type in ( - (issue_first_grant_id, "AdminRoleGrantIssued"), - (revoke_second_grant_id, "AdminRoleGrantRevoked"), - (revoke_first_grant_id, "AdminRoleGrantRevoked"), - ): - success_ids = ( - await session.scalars( - select(AuditEvent.id).where( - AuditEvent.entity_id == resource_id, - AuditEvent.event_type == event_type, - ) - ) - ).all() - linked_count = 0 - for success_id in success_ids: - linked_count += int( - await session.scalar( - select(func.count()) - .select_from(AuditEvent) - .where(AuditEvent.invalidation_cause_event_id == success_id) - ) - or 0 - ) - linked_pair_counts[(resource_id, event_type)] = linked_count - assert len(success_ids) == 1 - denied_second_issue = int( - await session.scalar( - select(func.count()) - .select_from(AuditEvent) - .where( - AuditEvent.event_type == "SensitiveAuthorizationDenied", - AuditEvent.action_id == "admin_role_grant.issue", - AuditEvent.resource_id == str(profiles["pm-target-two"]), - ) - ) - or 0 - ) - forbidden_second_issue_state = int( - await session.scalar( - select(func.count()) - .select_from(AuditEvent) - .where( - ( - (AuditEvent.event_type == "AdminRoleGrantIssued") - & (AuditEvent.target_actor_ref == str(profiles["pm-target-two"])) - ) - | ( - (AuditEvent.event_type == "AuthorityInvalidationRequested") - & (AuditEvent.invalidation_target_ref == str(profiles["pm-target-two"])) - ) - ) - ) - or 0 - ) - assert active_admins == 1 - assert event_counts == { - "InitialAccessAdministratorBootstrapped": 1, - "AdminRoleGrantIssued": 6, - "AdminRoleGrantRevoked": 3, - "AdminRoleGrantIssueDenied": 2, - } - assert set(linked_pair_counts.values()) == {1} - assert denied_second_issue == 1 - assert forbidden_second_issue_state == 0 - await db_session.dispose_engine() - - -async def test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure( - auth_database_env: str, - rsa_signing_material: tuple[rsa.RSAPrivateKey, dict[str, Any]], - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Prove lifecycle and grant changes serialize after both bounded reads.""" - private_key, jwk = rsa_signing_material - settings = production_verifier_settings(database_url=auth_database_env) - app = create_app(settings) - app.state.auth_verifier = FlowAuthVerifier(settings, jwks_transport=jwks_transport(jwk)) - reader_token = issue_asymmetric_token( - private_key, - claims={"sub": "auth09c-profile-reader", "jti": "auth09c-profile-reader-token"}, - ) - link_reader_token = issue_asymmetric_token( - private_key, - claims={"sub": "auth09c-link-reader", "jti": "auth09c-link-reader-token"}, - ) - custodian_token = issue_asymmetric_token( - private_key, - claims={"sub": "auth09c-custodian", "jti": "auth09c-custodian-token"}, - ) - target_token = issue_asymmetric_token( - private_key, - claims={"sub": "auth09c-target", "jti": "auth09c-target-token"}, - ) - reader_headers = {"Authorization": f"Bearer {reader_token}"} - link_reader_headers = {"Authorization": f"Bearer {link_reader_token}"} - custodian_headers = {"Authorization": f"Bearer {custodian_token}"} - pause_kind: str | None = None - entered = asyncio.Event() - release = asyncio.Event() - transition_backend_pids: asyncio.Queue[int] = asyncio.Queue() - captured_grant_transition_tasks: set[asyncio.Task] = set() - original_profile_read = ActorService.read_admin_profile - original_link_read = ActorService.read_admin_identity_link - original_get_grant = AdminAuthorizationRepository.get_grant - - async def pause_profile_read(service: ActorService, actor_profile_id: UUID): - if pause_kind == "profile": - entered.set() - await release.wait() - return await original_profile_read(service, actor_profile_id) - - async def pause_link_read(service: ActorService, actor_profile_id: UUID): - if pause_kind == "identity_link": - entered.set() - await release.wait() - return await original_link_read(service, actor_profile_id) - - async def capture_grant_transition_backend(repository, *args, **kwargs): - task = asyncio.current_task() - if ( - task is not None - and task.get_name() == "auth09c-grant-revocation-transition" - and task not in captured_grant_transition_tasks - ): - captured_grant_transition_tasks.add(task) - backend_pid = await repository._session.scalar(text("select pg_backend_pid()")) - transition_backend_pids.put_nowait(int(backend_pid)) - return await original_get_grant(repository, *args, **kwargs) - - monkeypatch.setattr(ActorService, "read_admin_profile", pause_profile_read) - monkeypatch.setattr(ActorService, "read_admin_identity_link", pause_link_read) - monkeypatch.setattr( - AdminAuthorizationRepository, - "get_grant", - capture_grant_transition_backend, - ) - - async def capture_transition_backend(session: AsyncSession) -> None: - backend_pid = await session.scalar(text("select pg_backend_pid()")) - transition_backend_pids.put_nowait(int(backend_pid)) - - async def actor_timestamps(actor_id: UUID) -> tuple[datetime | None, datetime | None]: - async with db_session.get_session_factory()() as session: - return tuple( - ( - await session.execute( - text( - "select p.last_seen_at,l.last_verified_at from actor_profiles p " - "join actor_identity_links l on l.actor_profile_id=p.id " - "where p.id=:actor" - ), - {"actor": str(actor_id)}, - ) - ).one() - ) - - async def set_profile_state(actor_id: UUID, custodian_id: UUID, state: str) -> None: - async with db_session.get_session_factory()() as session: - await capture_transition_backend(session) - if state == "suspended": - statement = ( - "update actor_profiles set status='suspended',suspended_by=:by," - "suspended_at=clock_timestamp(),suspension_reason='race proof' " - "where id=:actor" - ) - else: - statement = ( - "update actor_profiles set status='deactivated',deactivated_by=:by," - "deactivated_at=clock_timestamp(),deactivation_reason='race proof' " - "where id=:actor" - ) - await session.execute( - text(statement), {"actor": str(actor_id), "by": str(custodian_id)} - ) - await session.commit() - - async def reset_profile(actor_id: UUID) -> None: - async with db_session.get_session_factory()() as session: - await session.execute(text("alter table actor_profiles disable trigger user")) - await session.execute( - text( - "update actor_profiles set status='active',suspended_by=null," - "suspended_at=null,suspension_reason=null,deactivated_by=null," - "deactivated_at=null,deactivation_reason=null,reactivated_by=null," - "reactivated_at=null,reactivation_reason=null where id=:actor" - ), - {"actor": str(actor_id)}, - ) - await session.execute(text("alter table actor_profiles enable trigger user")) - await session.commit() - - async def revoke_link(actor_id: UUID, custodian_id: UUID) -> None: - async with db_session.get_session_factory()() as session: - await capture_transition_backend(session) - await session.execute( - text( - "update actor_identity_links set status='revoked',revoked_by=:by," - "revoked_at=clock_timestamp(),revoked_reason='race proof' " - "where actor_profile_id=:actor" - ), - {"actor": str(actor_id), "by": str(custodian_id)}, - ) - await session.commit() - - async def reset_link(actor_id: UUID) -> None: - async with db_session.get_session_factory()() as session: - await session.execute(text("alter table actor_identity_links disable trigger user")) - await session.execute( - text( - "update actor_identity_links set status='active',revoked_by=null," - "revoked_at=null,revoked_reason=null,reactivated_by=null," - "reactivated_at=null,reactivation_reason=null " - "where actor_profile_id=:actor" - ), - {"actor": str(actor_id)}, - ) - await session.execute(text("alter table actor_identity_links enable trigger user")) - await session.commit() - - async def wait_for_transition_lock( - transition_task: asyncio.Task, - transition_backend_pid: int, - ) -> None: - for _ in range(250): - if transition_task.done(): - raise AssertionError("disabling transition bypassed the read lock") - async with db_session.get_session_factory()() as session: - waiting = await session.scalar( - text("select coalesce(cardinality(pg_blocking_pids(:pid)),0)>0"), - {"pid": transition_backend_pid}, - ) - if waiting: - return - await asyncio.sleep(0.02) - raise AssertionError("disabling transition never reached a PostgreSQL lock wait") - - async with AsyncClient( - transport=ASGITransport(app=app), - base_url="http://testserver", - ) as client: - reader = await client.get("/api/v1/actors/me", headers=reader_headers) - link_reader = await client.get("/api/v1/actors/me", headers=link_reader_headers) - custodian = await client.get("/api/v1/actors/me", headers=custodian_headers) - target = await client.get( - "/api/v1/actors/me", - headers={"Authorization": f"Bearer {target_token}"}, - ) - reader_id = UUID(reader.json()["actor_profile_id"]) - link_reader_id = UUID(link_reader.json()["actor_profile_id"]) - custodian_id = UUID(custodian.json()["actor_profile_id"]) - target_id = UUID(target.json()["actor_profile_id"]) - bootstrap_code, _bootstrap = await run_admin_bootstrap(custodian_id, execute=True) - assert bootstrap_code == 0 - reader_grants: dict[UUID, str] = {} - for current_reader_id in (reader_id, link_reader_id): - reader_grant = await client.post( - "/api/v1/admin-role-grants", - headers={**custodian_headers, "Idempotency-Key": str(uuid4())}, - json={ - "target_actor_profile_id": str(current_reader_id), - "role": "access_administrator", - "scope_type": "system", - "scope_project_id": None, - "reason": "AUTH-09C concurrency reader", - }, - ) - assert reader_grant.status_code == 201, reader_grant.text - reader_grants[current_reader_id] = reader_grant.json()["resource_id"] - - for current_kind, path_suffix, current_headers, current_reader_id in ( - ("profile", "", reader_headers, reader_id), - ("identity_link", "/identity-links", link_reader_headers, link_reader_id), - ): - current_grant_id = reader_grants[current_reader_id] - for transition in ("suspended", "link_revoked", "grant_revoked", "deactivated"): - pause_kind = current_kind - entered = asyncio.Event() - release = asyncio.Event() - read_task = asyncio.create_task( - client.get( - f"/api/v1/actors/{target_id}{path_suffix}", - headers=current_headers, - ) - ) - await asyncio.wait_for(entered.wait(), timeout=5) - if transition in {"suspended", "deactivated"}: - transition_task = asyncio.create_task( - set_profile_state(current_reader_id, custodian_id, transition) - ) - elif transition == "link_revoked": - transition_task = asyncio.create_task( - revoke_link(current_reader_id, custodian_id) - ) - else: - transition_task = asyncio.create_task( - client.post( - f"/api/v1/admin-role-grants/{current_grant_id}/revoke", - headers={ - **custodian_headers, - "Idempotency-Key": str(uuid4()), - }, - json={"reason": "AUTH-09C matched grant race"}, - ), - name="auth09c-grant-revocation-transition", - ) - transition_backend_pid = await asyncio.wait_for( - transition_backend_pids.get(), - timeout=5, - ) - await wait_for_transition_lock(transition_task, transition_backend_pid) - release.set() - read_response = await read_task - transition_result = await transition_task - assert read_response.status_code == 200, read_response.text - if transition == "grant_revoked": - assert transition_result.status_code == 200, transition_result.text - disabled_timestamps = await actor_timestamps(current_reader_id) - denied = await client.get( - f"/api/v1/actors/{target_id}{path_suffix}", - headers=current_headers, - ) - assert denied.status_code == 403 - assert await actor_timestamps(current_reader_id) == disabled_timestamps - - if transition in {"suspended", "deactivated"}: - if transition == "suspended": - await reset_profile(current_reader_id) - elif transition == "link_revoked": - await reset_link(current_reader_id) - else: - replacement = await client.post( - "/api/v1/admin-role-grants", - headers={ - **custodian_headers, - "Idempotency-Key": str(uuid4()), - }, - json={ - "target_actor_profile_id": str(current_reader_id), - "role": "access_administrator", - "scope_type": "system", - "scope_project_id": None, - "reason": "Restore AUTH-09C reader authority", - }, - ) - assert replacement.status_code == 201, replacement.text - current_grant_id = replacement.json()["resource_id"] - pause_kind = None - - async def test_controlled_endpoint_provisions_review_and_adapter_target_identities( auth_database_env: str, rsa_signing_material: tuple[rsa.RSAPrivateKey, dict[str, Any]], diff --git a/backend/tests/test_ci_lane_catalogue.py b/backend/tests/test_ci_lane_catalogue.py index d17b48b62..f7cac1e1e 100644 --- a/backend/tests/test_ci_lane_catalogue.py +++ b/backend/tests/test_ci_lane_catalogue.py @@ -130,6 +130,16 @@ def test_measured_hotspots_have_explicit_semantic_owners() -> None: } == modules_by_lane["schema_contracts"] assert { "tests/authorization/admin_access/test_bootstrap_cli.py", + "tests/authorization/admin_access/test_api_journey.py", + "tests/authorization/admin_access/test_bootstrap_postgresql.py", + "tests/authorization/admin_access/test_admin_reads_postgresql.py", + "tests/authorization/admin_access/test_grant_api_postgresql.py", + "tests/authorization/admin_access/test_grant_reads_postgresql.py", + "tests/authorization/admin_access/test_grant_validation_postgresql.py", + "tests/authorization/admin_access/test_failure_atomicity_postgresql.py", + "tests/authorization/admin_access/test_grant_concurrency_postgresql.py", + "tests/authorization/admin_access/test_timestamp_concurrency_postgresql.py", + "tests/authorization/admin_access/test_read_concurrency_postgresql.py", "tests/actors/test_first_access_postgresql.py", "tests/authorization/guide_compilation_projections/test_replay_evidence.py", "tests/test_auth_concurrency_observer.py", From 9c43303ce94f706a6beb340251f47c486232c947 Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Tue, 8 Sep 2026 00:52:52 +0100 Subject: [PATCH 5/6] test(auth): bind fault injection to grant transaction custody --- .../initiatives/WS-QUAL-003/WS-QUAL-003-13.md | 14 ++++++++++ .../admin_access/concurrency_support.py | 25 ++++++++++++++++++ .../admin_access/fault_support.py | 24 ++++++++++++++--- .../test_failure_atomicity_postgresql.py | 2 +- .../admin_access/test_grant_api_postgresql.py | 5 ++-- .../test_grant_concurrency_postgresql.py | 26 ++++++++++++++++++- .../test_read_concurrency_postgresql.py | 2 +- 7 files changed, 90 insertions(+), 8 deletions(-) diff --git a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md index 0278fe127..68206e144 100644 --- a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md +++ b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md @@ -189,6 +189,7 @@ Parameter cases must remain independently identifiable in final assertion map. | Target sees granted role but cannot read protected definitions | `test_target_role_projection_does_not_grant_catalogue_access` | Real grants reflected in self-read; definitions403/permission_not_granted | | Read query and grant request validation | `test_invalid_admin_request_is_bounded` | Preserve individually mapped original invalid field/cursor/selector cases | | Concurrent bootstrap has one winner | `test_concurrent_bootstrap_has_one_persisted_winner` | Two sessions, exact control-lock wait, grant/control/success event and losing conflict | +| Race proof detects a missing owner lock | `test_bootstrap_race_proof_rejects_missing_owner_lock` | Hosted-only negative control removes exactly the real owner's FOR UPDATE in memory; the unchanged race proof must fail specifically at exact-lock observation, not setup or timeout; monkeypatch restored | | Same-key concurrency recovers | `test_concurrent_same_key_grant_returns_one_result` | Exact reservation wait, matching outputs, one grant and evidence pair | | Distinct-key concurrency cannot double issue | `test_concurrent_distinct_keys_create_one_active_grant` | Exact control wait, 201/409, one persisted grant | | Cross-revoke retains effective administrator | `test_cross_revoke_retains_one_effective_admin` | Exact control wait, one revoke and one denied caller, one effective surviving administrator | @@ -286,3 +287,16 @@ CLI privacy and empty-stderr proof remain unchanged from the first checkpoint. All new PostgreSQL modules are explicitly registered in existing hosted lanes. This checkpoint still requires hosted PostgreSQL results, fault/lock probes, and affected exact-head reviews before the PR can be reported ready. + +The hosted negative-control test mutates the real control-lock method only in +test memory and requires the unchanged bootstrap race proof to reject it at +its observer. Access-administrator issuance is also an explicit grant evidence +case, so typed issue/invalidation protection is not hidden in setup alone. + +The first hosted execution exposed two test assumptions: persisted audit actor +attribution is `actor_id` (not the audit input's `actor_ref`), and the first +mutation-route commit may belong to independent rate control. Grant fault +injection now captures the real grant service's session and fails only its +commit. The unchanged staged-state assertions rejected the earlier hook because +issue had staged no grant and revoke still showed active state. This supplies +an executed early-failure counterexample rather than a mock-only rollback claim. diff --git a/backend/tests/authorization/admin_access/concurrency_support.py b/backend/tests/authorization/admin_access/concurrency_support.py index 7a4ddcab5..bb173bf24 100644 --- a/backend/tests/authorization/admin_access/concurrency_support.py +++ b/backend/tests/authorization/admin_access/concurrency_support.py @@ -1,8 +1,11 @@ """Hold the actual owner lock until an independent observer sees the exact waiter.""" +import ast import asyncio from collections.abc import Awaitable, Callable from dataclasses import dataclass +import inspect +import textwrap from typing import Any from uuid import uuid4 @@ -11,6 +14,7 @@ from app.db import session as db_session from app.modules.actors.service import ActorService +from app.modules.authorization import repository as authorization_repository from app.modules.authorization.repository import ( AdminAuthorizationRepository, @@ -28,6 +32,27 @@ class LockObservation: observed: bool = False +def control_owner_without_row_lock(): + """Mutate only the real owner's FOR UPDATE for the hosted negative control.""" + source = inspect.getsource(AdminAuthorizationRepository.lock_control) + tree = ast.parse(textwrap.dedent(source)) + removed = [] + + class RemoveLock(ast.NodeTransformer): + def visit_Call(self, node): + node = self.generic_visit(node) + if isinstance(node.func, ast.Attribute) and node.func.attr == "with_for_update": + removed.append(node) + return node.func.value + return node + + tree = ast.fix_missing_locations(RemoveLock().visit(tree)) + assert len(removed) == 1, "probe must remove exactly the owner's control-row lock" + namespace = dict(vars(authorization_repository)) + exec(compile(tree, "", "exec"), namespace) + return namespace["lock_control"] + + async def ordered_owner_calls( first: Callable[[], Awaitable[Any]], second: Callable[[], Awaitable[Any]], diff --git a/backend/tests/authorization/admin_access/fault_support.py b/backend/tests/authorization/admin_access/fault_support.py index e8c5deb63..1caeb13e2 100644 --- a/backend/tests/authorization/admin_access/fault_support.py +++ b/backend/tests/authorization/admin_access/fault_support.py @@ -10,6 +10,7 @@ from app.modules.actors.service import ActorService from app.modules.audit.service import AuditService +from app.modules.authorization.admin_service import AdminRoleGrantService from tests.authorization.admin_access.read_support import READ_ACTIONS from tests.authorization.admin_access.support import ( ActorObservation, @@ -30,15 +31,32 @@ async def capture(self, session: AsyncSession) -> None: self.actor = await observed_actor(session, self.actor_id) -def fail_next_commit(monkeypatch: pytest.MonkeyPatch, actor_id: UUID) -> FailureObservation: - """Do not synthesize writes; inspect the actual first commit's transaction.""" +def fail_next_commit( + monkeypatch: pytest.MonkeyPatch, + actor_id: UUID, + *, + grant_operation: str | None = None, +) -> FailureObservation: + """Fail the feature commit, not an independent mutation rate-control commit.""" probe = FailureObservation(actor_id) original = AsyncSession.commit attempted = False + owner_session: AsyncSession | None = None + if grant_operation is not None: + assert grant_operation in {"issue", "revoke"} + method = f"complete_{grant_operation}" + complete = getattr(AdminRoleGrantService, method) + + async def remember_owner(service, *args, **kwargs): + nonlocal owner_session + owner_session = service._session + return await complete(service, *args, **kwargs) + + monkeypatch.setattr(AdminRoleGrantService, method, remember_owner) async def fail_commit(session): nonlocal attempted - if attempted: + if attempted or (grant_operation is not None and session is not owner_session): return await original(session) attempted = True await probe.capture(session) diff --git a/backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py b/backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py index 502e0afad..db864b782 100644 --- a/backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py +++ b/backend/tests/authorization/admin_access/test_failure_atomicity_postgresql.py @@ -112,7 +112,7 @@ async def test_grant_mutation_commit_failure_rolls_back( before_actor = await seed_old_observation(access.admin.id) before = await authority_snapshot() key = str(uuid4()) - probe = fail_next_commit(monkeypatch, access.admin.id) + probe = fail_next_commit(monkeypatch, access.admin.id, grant_operation=operation) if operation == "issue": response = await access.signed.issue(access.admin, body, key=key) else: diff --git a/backend/tests/authorization/admin_access/test_grant_api_postgresql.py b/backend/tests/authorization/admin_access/test_grant_api_postgresql.py index d4fa85576..00ff00a88 100644 --- a/backend/tests/authorization/admin_access/test_grant_api_postgresql.py +++ b/backend/tests/authorization/admin_access/test_grant_api_postgresql.py @@ -23,6 +23,7 @@ ("issue", "project_manager", True), ("issue", "audit_authority", True), ("issue", "audit_authority", False), + ("issue", "access_administrator", False), ("revoke", "operator", False), ], ) @@ -73,7 +74,7 @@ async def test_grant_mutation_exact_replay_has_one_effect( ] assert len(success) == 1 assert success[0]["entity_id"] == first.json()["resource_id"] - assert success[0]["actor_ref"] == str(access.admin.id) + assert success[0]["actor_id"] == str(access.admin.id) assert str(success[0]["idempotency_reference"]) == str(records[0]["id"]) invalidations = [e for e in events if e["event_type"] == "AuthorityInvalidationRequested"] assert len(invalidations) == 1 @@ -160,7 +161,7 @@ async def test_grant_mutation_mismatch_preserves_product_state( assert len(added) == 1 assert added[0]["event_type"] == "SensitiveAuthorizationDenied" assert added[0]["denial_code"] == "idempotency_mismatch" - assert added[0]["actor_ref"] == str(access.admin.id) + assert added[0]["actor_id"] == str(access.admin.id) assert added[0]["action_id"] == f"admin_role_grant.{operation}" diff --git a/backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py b/backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py index 7ebbe0f71..c0b11ba15 100644 --- a/backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py +++ b/backend/tests/authorization/admin_access/test_grant_concurrency_postgresql.py @@ -5,7 +5,11 @@ import pytest from scripts.bootstrap_access_administrator import _run as run_bootstrap -from tests.authorization.admin_access.concurrency_support import ordered_owner_calls +from app.modules.authorization.repository import AdminAuthorizationRepository +from tests.authorization.admin_access.concurrency_support import ( + control_owner_without_row_lock, + ordered_owner_calls, +) from tests.authorization.admin_access.support import ( AdminAccess, SignedAccess, @@ -52,6 +56,26 @@ async def test_concurrent_bootstrap_has_one_persisted_winner( assert conflicts[0]["target_actor_ref"] == str(second.id) +async def test_bootstrap_race_proof_rejects_missing_owner_lock( + signed_access: SignedAccess, + auth_database_env: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + broken_owner = control_owner_without_row_lock() + with monkeypatch.context() as patch: + patch.setattr(AdminAuthorizationRepository, "lock_control", broken_owner) + with pytest.raises(AssertionError, match="actual owner lock observation failed") as failure: + await test_concurrent_bootstrap_has_one_persisted_winner( + signed_access, + auth_database_env, + monkeypatch, + ) + assert isinstance(failure.value.__cause__, AssertionError) + assert ( + str(failure.value.__cause__) == "ordered lifecycle request never reached the database lock" + ) + + async def test_concurrent_same_key_grant_returns_one_result( admin_access: AdminAccess, auth_database_env: str, diff --git a/backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py b/backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py index 94278610d..52da15030 100644 --- a/backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py +++ b/backend/tests/authorization/admin_access/test_read_concurrency_postgresql.py @@ -43,7 +43,7 @@ async def test_admin_read_blocks_exact_authority_transition( action, _ = READ_ACTIONS[surface] events = await authority_events(action=action, event_type="SensitiveAuthorizationAllowed") assert len(events) == 1 - assert events[0].actor_ref == str(reader.id) + assert events[0].actor_id == str(reader.id) assert events[0].matched_grant_id == grant_id denied = await access.signed.client.get( read_path(access.target.id, surface), headers=reader.headers From 225ffd2bcf382e7c86a63f574c97b967afc07b3f Mon Sep 17 00:00:00 2001 From: Commitrail Probe Date: Tue, 8 Sep 2026 01:10:44 +0100 Subject: [PATCH 6/6] test(auth): close typed grant proof and reconcile audit outcome --- .../assertion-maps/WS-QUAL-003-13.json | 22 +++++++++---------- .../initiatives/WS-QUAL-003/OVERVIEW.md | 21 +++++++++++++----- .../initiatives/WS-QUAL-003/WS-QUAL-003-13.md | 21 ++++++++++++++---- .../admin_access/test_grant_api_postgresql.py | 10 +++++++++ docs/roadmap_status.md | 5 ++++- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json b/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json index c32de562f..faa66a00b 100644 --- a/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json +++ b/.ci/auth-boundaries/assertion-maps/WS-QUAL-003-13.json @@ -186,18 +186,18 @@ {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1732:1732:e609834893123f120a156dca27feb569cb76bc79c6f4409c1c8a5ce31bf1efd6","old_source_span":[1732,1732],"old_content_sha256":"e609834893123f120a156dca27feb569cb76bc79c6f4409c1c8a5ce31bf1efd6","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1768:1768:adea16d475647a5ddf6c5bc49b9f4021cb7c8130274048e372275ba04f33d563","old_source_span":[1768,1768],"old_content_sha256":"adea16d475647a5ddf6c5bc49b9f4021cb7c8130274048e372275ba04f33d563","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1769:1774:1cd08560946f2aa00d333e076cd6a555c172f7776f3f49cdb401ca55b592720a","old_source_span":[1769,1774],"old_content_sha256":"1cd08560946f2aa00d333e076cd6a555c172f7776f3f49cdb401ca55b592720a","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1796:1796:4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","old_source_span":[1796,1796],"old_content_sha256":"4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1865:1865:17d2fa2835e23a18f95b838daac7dc68bec4cc625aa11545c044d65d67810a1f","old_source_span":[1865,1865],"old_content_sha256":"17d2fa2835e23a18f95b838daac7dc68bec4cc625aa11545c044d65d67810a1f","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1866:1866:6bbecb8449be355265b77461b498f0118aa20bb450bf1ca91c60d3a053d43b70","old_source_span":[1866,1866],"old_content_sha256":"6bbecb8449be355265b77461b498f0118aa20bb450bf1ca91c60d3a053d43b70","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1877:1877:0a8d3fcd723db576987edc2d0974d17024f4093bc42a387cd84755f1dd53715a","old_source_span":[1877,1877],"old_content_sha256":"0a8d3fcd723db576987edc2d0974d17024f4093bc42a387cd84755f1dd53715a","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1878:1878:5f46e023d3a84db670f65960ee5d02a313ab1e37c0b71e53b99e7a49d16be543","old_source_span":[1878,1878],"old_content_sha256":"5f46e023d3a84db670f65960ee5d02a313ab1e37c0b71e53b99e7a49d16be543","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1879:1879:a52256849581efd03fac92e1a9e767598a3ad0f8b22fc37e18eccd2d13778f22","old_source_span":[1879,1879],"old_content_sha256":"a52256849581efd03fac92e1a9e767598a3ad0f8b22fc37e18eccd2d13778f22","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1931:1931:e6c63b223a08a1ff685b1f394ba288ad5f6e381125f0506fc0f18e41ece4f35d","old_source_span":[1931,1931],"old_content_sha256":"e6c63b223a08a1ff685b1f394ba288ad5f6e381125f0506fc0f18e41ece4f35d","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1796:1796:4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","old_source_span":[1796,1796],"old_content_sha256":"4501a07961480e04645df6df94e3f878dea86506fc386bbd5e042a02655f45d2","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1865:1865:17d2fa2835e23a18f95b838daac7dc68bec4cc625aa11545c044d65d67810a1f","old_source_span":[1865,1865],"old_content_sha256":"17d2fa2835e23a18f95b838daac7dc68bec4cc625aa11545c044d65d67810a1f","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1866:1866:6bbecb8449be355265b77461b498f0118aa20bb450bf1ca91c60d3a053d43b70","old_source_span":[1866,1866],"old_content_sha256":"6bbecb8449be355265b77461b498f0118aa20bb450bf1ca91c60d3a053d43b70","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1877:1877:0a8d3fcd723db576987edc2d0974d17024f4093bc42a387cd84755f1dd53715a","old_source_span":[1877,1877],"old_content_sha256":"0a8d3fcd723db576987edc2d0974d17024f4093bc42a387cd84755f1dd53715a","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1878:1878:5f46e023d3a84db670f65960ee5d02a313ab1e37c0b71e53b99e7a49d16be543","old_source_span":[1878,1878],"old_content_sha256":"5f46e023d3a84db670f65960ee5d02a313ab1e37c0b71e53b99e7a49d16be543","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1879:1879:a52256849581efd03fac92e1a9e767598a3ad0f8b22fc37e18eccd2d13778f22","old_source_span":[1879,1879],"old_content_sha256":"a52256849581efd03fac92e1a9e767598a3ad0f8b22fc37e18eccd2d13778f22","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1931:1931:e6c63b223a08a1ff685b1f394ba288ad5f6e381125f0506fc0f18e41ece4f35d","old_source_span":[1931,1931],"old_content_sha256":"e6c63b223a08a1ff685b1f394ba288ad5f6e381125f0506fc0f18e41ece4f35d","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1961:1961:8b20d628974b6e826a17657405fdb73ac5621091d58580ee13a564af7d0bd42f","old_source_span":[1961,1961],"old_content_sha256":"8b20d628974b6e826a17657405fdb73ac5621091d58580ee13a564af7d0bd42f","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_cross_revoke_retains_one_effective_admin","invariant_category":"cross_revoke_retains_one_effective_admin","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This cross_revoke_retains_one_effective_admin assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1962:1967:aac9ecf6e18c4e4e2a6a0fbed938adf99427128bc0061cf83ef42ee7d11ddb2b","old_source_span":[1962,1967],"old_content_sha256":"aac9ecf6e18c4e4e2a6a0fbed938adf99427128bc0061cf83ef42ee7d11ddb2b","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Shared-history event totals decomposed: bootstrap success/conflict in test_concurrent_bootstrap_has_one_persisted_winner; same-key issue in test_concurrent_same_key_grant_returns_one_result; duplicate issue/denial in test_concurrent_distinct_keys_create_one_active_grant; cross-revoke in test_cross_revoke_retains_one_effective_admin; both issue/revoke orders here. Exact per-effect counts replace incidental fixture aggregate.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1968:1968:4c6e959ec302fee13a375e96b4aebefa6bbece07c3b340c58d97a07f11f3ae23","old_source_span":[1968,1968],"old_content_sha256":"4c6e959ec302fee13a375e96b4aebefa6bbece07c3b340c58d97a07f11f3ae23","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1969:1969:b281467fa2851b3de536939c3095a4a0180a938bca655f15b1a2a3fb2757d4f3","old_source_span":[1969,1969],"old_content_sha256":"b281467fa2851b3de536939c3095a4a0180a938bca655f15b1a2a3fb2757d4f3","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, - {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1970:1970:dcb078e3f7f67ed92f063ecfca34e4166f43733dcc925c10fbb338dbbeeec1fe","old_source_span":[1970,1970],"old_content_sha256":"dcb078e3f7f67ed92f063ecfca34e4166f43733dcc925c10fbb338dbbeeec1fe","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup is enforced by real grant helper.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1962:1967:aac9ecf6e18c4e4e2a6a0fbed938adf99427128bc0061cf83ef42ee7d11ddb2b","old_source_span":[1962,1967],"old_content_sha256":"aac9ecf6e18c4e4e2a6a0fbed938adf99427128bc0061cf83ef42ee7d11ddb2b","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Shared-history event totals decomposed: bootstrap success/conflict in test_concurrent_bootstrap_has_one_persisted_winner; same-key issue in test_concurrent_same_key_grant_returns_one_result; duplicate issue/denial in test_concurrent_distinct_keys_create_one_active_grant; cross-revoke in test_cross_revoke_retains_one_effective_admin; both issue/revoke orders here; typed access-administrator issuance and linked invalidation in test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False]. Exact per-effect counts replace incidental fixture aggregate.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1968:1968:4c6e959ec302fee13a375e96b4aebefa6bbece07c3b340c58d97a07f11f3ae23","old_source_span":[1968,1968],"old_content_sha256":"4c6e959ec302fee13a375e96b4aebefa6bbece07c3b340c58d97a07f11f3ae23","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1969:1969:b281467fa2851b3de536939c3095a4a0180a938bca655f15b1a2a3fb2757d4f3","old_source_span":[1969,1969],"old_content_sha256":"b281467fa2851b3de536939c3095a4a0180a938bca655f15b1a2a3fb2757d4f3","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, + {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_admin_bootstrap_replay_and_cross_revoke_are_concurrency_safe","old_assertion_id":"assertion:1970:1970:dcb078e3f7f67ed92f063ecfca34e4166f43733dcc925c10fbb338dbbeeec1fe","old_source_span":[1970,1970],"old_content_sha256":"dcb078e3f7f67ed92f063ecfca34e4166f43733dcc925c10fbb338dbbeeec1fe","new_test_node":"tests/authorization/admin_access/test_grant_concurrency_postgresql.py::test_issue_against_revocation_obeys_lock_order","invariant_category":"issue_against_revocation_obeys_lock_order: Both winner orders independently; successful issue/revocation exact linked events; revoked-first issue exactly one denial, no reservation/grant/invalidation. Positive second-admin setup uses the real grant helper; typed persisted issuance and linked invalidation are independently asserted by test_grant_mutation_exact_replay_has_one_effect[issue-access_administrator-False].","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This issue_against_revocation_obeys_lock_order assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2159:2159:d87c0219fc92b124096bf360534a2e340f2d761ddbf207bce50acf9de469052d","old_source_span":[2159,2159],"old_content_sha256":"d87c0219fc92b124096bf360534a2e340f2d761ddbf207bce50acf9de469052d","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2173:2173:6dce1bc0c02aadfd584523b98af65c756763668bd573298ce01178609156840d","old_source_span":[2173,2173],"old_content_sha256":"6dce1bc0c02aadfd584523b98af65c756763668bd573298ce01178609156840d","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, {"old_revision":"0e34911be4cdc25b3ec79dbcb097b62181958304","old_test_node":"tests/test_auth.py::test_actor_admin_reads_hold_caller_and_grant_locks_through_disclosure","old_assertion_id":"assertion:2220:2220:a814b4c43bf407658a1bdc7f6b5c1803ccdb296b30f969d0d66ba5f1b3eb2888","old_source_span":[2220,2220],"old_content_sha256":"a814b4c43bf407658a1bdc7f6b5c1803ccdb296b30f969d0d66ba5f1b3eb2888","new_test_node":"tests/authorization/admin_access/test_read_concurrency_postgresql.py::test_admin_read_blocks_exact_authority_transition","invariant_category":"admin_read_blocks_exact_authority_transition: Profile/link x suspended/deactivated/link_revoked/grant_revoked. Each case creates a fresh bootstrap/reader grant through real owners; old replacement-grant setup is unnecessary because no shared revoked row is reset. Denied subsequent read cannot observe or add allow evidence; exact reader PID blocks transition.","target_layer":"integration","security_dimensions":{"concurrency":"preserved","lock_order":"preserved","denial_side_effects":"preserved","replay":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no replay claim; other independently mapped cases own that dimension."},"revocation":"preserved","evidence":"preserved","transaction_ownership":"preserved","concealment":{"not_applicable_reason":"This admin_read_blocks_exact_authority_transition assertion makes no concealment claim; other independently mapped cases own that dimension."}}}, diff --git a/.commitrail/initiatives/WS-QUAL-003/OVERVIEW.md b/.commitrail/initiatives/WS-QUAL-003/OVERVIEW.md index 0a28e0f62..640356b7a 100644 --- a/.commitrail/initiatives/WS-QUAL-003/OVERVIEW.md +++ b/.commitrail/initiatives/WS-QUAL-003/OVERVIEW.md @@ -21,12 +21,15 @@ - AUTH cleanup: [12 — projection proof and staged AUTH audit](WS-QUAL-003-12.md). The human expanded this change to use reviewed commit checkpoints in one PR; projection proof is its first stage, not its completion boundary. -- After 12's intended merge outcome: inventory the remaining AUTH lifecycle - families before further decomposition; do not repeat the selected actor and - authentication proof audit. The full suite audit remains open. +- AUTH admin-access slice: [13 — lifecycle proof audit](WS-QUAL-003-13.md). +- After 13's intended merge outcome: inventory the remaining service-actor + provisioning and profile/link lifecycle families, then remaining AUTH owners. + Do not repeat the selected actor, authentication or admin-access audit. + The full suite audit remains open. - Preserve: intended production semantics, public boundaries, real database/isolation/ concurrency proof, current coverage floors, full hosted execution, human merge. -- Product work: POL-04A2 remains planned; this initiative does not implement it. +- Product work: POL-04A2 hidden finalization is delivered; its next AUTH-12B2 + activation boundary proceeds independently. This initiative implements neither. ## Baseline and honest audit coverage @@ -119,7 +122,15 @@ No fixed reduction percentage or same-day completion claim overrides safety. same change audits all 34 actor-registry tests and 51 authentication tests, removes the actor monolith, repairs real lock/rotation/rollback evidence and maps every original assertion. Its exact limits live in record 12; remaining - AUTH lifecycle families are unaudited. + AUTH lifecycle families beyond the selected slices are unaudited. +- AUTH slice 13 audits eight mixed bootstrap/admin-access tests and preserves + all 203 original assertion spans in named survivors. It retains the real + signed-token API journey, replaces arrival-only races with exact database + blocker proof, and checks actual staged state before injected commit failure. + A missing-owner-lock negative control calibrates the race proof. Fresh read + cases keep database triggers enabled instead of resetting shared lifecycle + rows. Three oversized functions are removed without moving them into helpers; + the remaining fifteen monolith test bodies are unchanged. - PROJECT slice 07 replaces the remaining mixed diagnostic composer tests with exact facts/digests and owner selectors. Each invalid-parent case now starts with a valid record, so a pre-existing missing target cannot hide a broken diff --git a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md index 68206e144..669fec6eb 100644 --- a/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md +++ b/.commitrail/initiatives/WS-QUAL-003/WS-QUAL-003-13.md @@ -1,7 +1,7 @@ # WS-QUAL-003-13 — Admin access lifecycle proof audit - Initiative: WS-QUAL-003 -- Durable disposition: Planned +- Durable disposition: Complete - Intended merge outcome: Eight mixed bootstrap/admin-access tests become bounded behavior proofs with a retained signed-token API journey and exact PostgreSQL concurrency/rollback custody. @@ -49,6 +49,9 @@ These are observed proof weaknesses, not established production defects. ### Allowed - This record and `WS-QUAL-003/OVERVIEW.md` for durable audit disposition. +- `docs/roadmap_status.md`: reconcile the selected audit's intended merged + outcome and remaining scope under the updated main roadmap rule. This + documentation-only scope correction does not expand the product change. - `backend/tests/test_auth.py`: remove only the eight named tests below, move its exact `auth_database_env` fixture to shared non-test support, re-import it for unchanged consumers, and remove only demonstrably dead imports. @@ -144,7 +147,8 @@ Destination paths below are relative to `tests/authorization/admin_access/`. ## Acceptance criteria -Every row is a future proof requirement, not an executed result. All database, +Every row defines the proof obligation; execution custody belongs to the PR. +All database, API and concurrency tests below run in hosted CI only; command tests are local. Parameter cases must remain independently identifiable in final assertion map. @@ -285,8 +289,8 @@ The old aggregate event counts are decomposed into exact operation-scoped succes denial and linked invalidation assertions; the map names the sibling survivors. CLI privacy and empty-stderr proof remain unchanged from the first checkpoint. All new PostgreSQL modules are explicitly registered in existing hosted lanes. -This checkpoint still requires hosted PostgreSQL results, fault/lock probes, -and affected exact-head reviews before the PR can be reported ready. +Readiness requires hosted PostgreSQL results, fault/lock probes, and affected +exact-head reviews; the PR records their current execution custody. The hosted negative-control test mutates the real control-lock method only in test memory and requires the unchanged bootstrap race proof to reject it at @@ -300,3 +304,12 @@ injection now captures the real grant service's session and fails only its commit. The unchanged staged-state assertions rejected the earlier hook because issue had staged no grant and revoke still showed active state. This supplies an executed early-failure counterexample rather than a mock-only rollback claim. + +Review corrections make exact recovery assert the persisted grant target, role, +scope and granting actor, not just a successful response and generic event. +The assertion map explicitly names the access-administrator parameter as the +typed issuance/invalidation survivor; setup alone does not own that evidence. +Current main's independent product registrations, schema fixtures and ledger +changes are preserved. The selected audit is complete as the intended merge +outcome; the remaining service-actor and profile/link families are not audited +by this record. No runtime defect or production correction is claimed here. diff --git a/backend/tests/authorization/admin_access/test_grant_api_postgresql.py b/backend/tests/authorization/admin_access/test_grant_api_postgresql.py index 00ff00a88..1c6d7e88b 100644 --- a/backend/tests/authorization/admin_access/test_grant_api_postgresql.py +++ b/backend/tests/authorization/admin_access/test_grant_api_postgresql.py @@ -56,6 +56,16 @@ async def test_grant_mutation_exact_replay_has_one_effect( assert after_actor.last_seen_at > before_actor.last_seen_at assert after_actor.last_verified_at > before_actor.last_verified_at after = await authority_snapshot() + stored_grant = next( + row + for row in after["admin_role_grants"] + if str(row["id"]) == first.json()["resource_id"] + ) + assert stored_grant["target_actor_profile_id"] == str(access.target.id) + assert stored_grant["role"] == role + assert stored_grant["scope_type"] == ("project" if project_scoped else "system") + assert stored_grant["scope_project_id"] == (str(project) if project is not None else None) + assert stored_grant["granted_by_actor_profile_id"] == str(access.admin.id) records = [ r for r in after["authority_idempotency_records"] if str(r["idempotency_key"]) == key ] diff --git a/docs/roadmap_status.md b/docs/roadmap_status.md index 4f789725b..a6b1bec50 100644 --- a/docs/roadmap_status.md +++ b/docs/roadmap_status.md @@ -243,7 +243,10 @@ not a claim that every test or subsystem is fully audited. The selected AUTH projection replay, actor-resolution, and authentication audit and decomposition are also delivered, including stronger first-access race -proof. That does not complete the remaining AUTH lifecycle families or the full +proof. The selected bootstrap/admin-access audit also retains signed API +composition, strengthens exact PostgreSQL lock and staged rollback proof, and +maps the replaced mixed assertions to bounded owner tests. That does not complete +the remaining service-actor, profile/link and other AUTH families or the full suite audit. Remaining work includes those AUTH families and the TASK, CHECKER, ART, CON, REV, and tooling audit. The audit requires behavioral proof, not only file splitting or coverage percentages. Real PostgreSQL, concurrency, storage,