Skip to content

fix(server): preserve permanent subject ownership - #167

Open
cariandrum22 wants to merge 2 commits into
mainfrom
fix/subject-ownership-history
Open

cariandrum22 wants to merge 2 commits into
mainfrom
fix/subject-ownership-history

Conversation

@cariandrum22

@cariandrum22 cariandrum22 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Preserve each case-sensitive OpenID Connect subject assignment within its issuer namespace and each end-user UUID across environments. Renaming or deleting a user cannot release its subject for another user; the original owner may return to a previously owned subject. This implements the non-reassignment requirements in OpenID Connect Core §2 and §5.7.

The migration adds immutable ownership, reservation, namespace and adoption records. Existing namespaces remain pending until a stopped, reviewed history import reconciles current users, attached audit history and explicitly supplied external sources. The CLI checks source hashes, the locked inventory, installed database definitions and privileges before committing ownership, receipt and audit records together.

Server construction creates its own restricted database pool and binds protected publication and identity/session operations to the validated issuer namespace. The public factory starts the required runtime monitors and signals embedding applications to drain on restart. Namespace refusal preserves cache-prevention headers. Health, discovery, keys, token revocation and unrelated management retain their existing admission rules.

Runtime audit-history checks cover the parent and every attached partition, including descendants in other schemas, and reject reachable ownership or rewrite privileges while preserving legitimate INSERT/SELECT. A forward migration updates these checks and their expected definitions without changing the original migration or existing adoption receipts. Both inventory paths fetch fixed batches of 256 rows. Restart notification also preserves requests that arrive before the waiter is first polled.

Validation

  • Earlier nix develop -c bash scripts/tests/run_server_container_integration.sh all stages passed Redis 53, pre-migration 1, PostgreSQL 191 and standalone DCR 1; after four fixture corrections, all 19 combined cases passed in a new owned database. Earlier cargo test --locked -p aegaeon-server --lib passed 1,832 tests, and four source-boundary integration suites passed. These broad results retain their original source/artifact identities and were not rerun after the follow-up production changes.
  • Follow-up checks passed 5 deterministic restart tests, 15 history tests and 2 real factory/listener lifecycle tests. The held request uses a test-only handler; 3 namespace and 20 actual product-handler acceptance successes are reused with their recorded source and binary identities.
  • Isolated PostgreSQL checks cover forward/fresh catalog and ACL parity; audit mutation refusal across roles and partition layouts; grant drift before adoption; rollback/commit; unchanged old-CLI adoption receipts after forward migration; and new public-factory acceptance. The factory and CLI reject an incorrect final migration hash. Prior CLI conflict, stale-input, audit rollback and classifier evidence remains scoped to its original runs.
  • Seven collection sizes through 769 rows in each inventory path retain exact snapshots and matching documents apart from tool provenance, with reduced FETCH calls. The predecessor control is the retained old executable; the normal control differs only in FETCH-1 batch size. Write/read failures, blocked-writer release and document-size refusal were exercised.
  • Final affected server all-target Clippy with -D warnings, formatting, server Clippy inventory, Python connection fixtures, documentation checks, Atlas validation and normal hooks passed. Earlier compliance-matrix and strict verified-reference checks are reused at their recorded source. Failed attempts remain retained; finite tests do not establish historical completeness.

Notes

Depends on #163. Follow docs/operations/subject-ownership.md before upgrading: provision separate migration/runtime/maintenance identities, stop and drain writers during cutover, retain complete historical sources and validate the final grants. Apply the forward migration to existing installations and remove any audit rewrite/ownership privileges reported by preflight before serving or adopting history; the migration does not silently repair deployment grants.

Replace AppState struct construction or external pool injection with AppState::from_environment().await?. Embedders must observe shutdown_requested() and drain their listener. New protected admissions refuse after restart; already-admitted work may finish during drain. Complete that drain before privileged database, schema, role or history changes, then construct a new validated runtime. Backups must preserve permanent authority records with identity history, roles, migration revisions and retained receipts; a stale restore requires stopped reconciliation before serving.

External history completeness and authenticity remain operator premises supported by retained sources and an authorized attestation. Private identity-history artifacts are not attached to this PR. The 256-row fetch bound does not bound the byte size of an arbitrary row.

Copilot AI balanced review requested due to automatic review settings October 2, 2026 15:01
@cariandrum22 cariandrum22 added bug Something isn't working documentation Improvements or additions to documentation spec Compliance matrix, registers and schemas security Security policy, reporting channels and hardening labels Oct 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Three critical and two moderate findings remain unresolved, affecting restart safety, audit-history protection, upgrade scalability, and pending-namespace responses.

Review effort: Balanced
Findings: 3 High severity · 1 Medium severity

Open (4)
What changed in this PR

Preserves permanent, issuer-scoped OIDC subject ownership and end-user UUID ownership across environments, with stopped-history reconciliation and namespace-bound server operations.

Changes:

  • Adds ownership records, restricted database provisioning, and history-adoption tooling.
  • Gates protected identity, token, and session operations on namespace validation.
  • Updates integration fixtures, regression tests, compliance records, and upgrade documentation.

Unresolved findings:

  • Critical: In-flight protected operations can publish after restart is requested; revalidate at commit/publication boundaries or cancel those workflows.
  • Critical: The shutdown notification can miss a restart signal; make checking and subscribing race-free.
  • Critical: Runtime privilege checks omit audit tables and partitions, allowing history modification; extend authority checks.
  • Moderate: Pre-migration inventory makes one database round trip per row while blocking writers; fetch bounded batches.
  • Moderate: User status transitions return 500 instead of the documented 503 for pending namespaces; apply the ownership error mapping and test a transition.
File Description
spec/​subject-ownership/​digest-vectors-v1.json Defines reproducible history-digest vectors.
spec/​compliance-matrix.yaml Records permanent-ownership requirements and coverage.
scripts/​tests/​test_subject_ownership_fixture.py Tests fixture connection boundaries.
scripts/​tests/​run_server_container_integration.sh Uses owned databases and restricted-role fixtures.
scripts/​operations/​provision-subject-ownership.sql Provisions and checks database authority.
pyproject.toml Configures unittest lint exceptions.
docs/​operations/​README.md Links the ownership runbook.
docs/​operations/​oidc-subject-format.md Connects subject-format validation to ownership adoption.
docs/​index.md Indexes the ownership runbook.
docs/​configurations/​environment/​federation-observability-and-test.md Documents database fixture settings.
db/​migrations/​atlas.sum Registers the ownership migration checksum.
crates/​server/​tests/​management_database_env_boundary_guard_test.rs Updates bootstrap source-boundary assertions.
crates/​server/​tests/​dcr_database_test.rs Preserves permanent namespace records.
crates/​server/​src/​web/​userinfo.rs Gates UserInfo publication.
crates/​server/​src/​web/​upstream_refresh.rs Gates upstream refresh operations.
crates/​server/​src/​web/​upstream_callback.rs Gates upstream callback processing.
crates/​server/​src/​web/​upstream_callback_users/​jit/​subject_tests.rs Checks JIT ownership and rollback state.
crates/​server/​src/​web/​upstream_authorize.rs Gates upstream authorization.
crates/​server/​src/​web/​token_refresh/​tests.rs Validates refresh fixture namespaces.
crates/​server/​src/​web/​token_refresh.rs Gates refresh grants.
crates/​server/​src/​web/​token_lifecycle.rs Gates token introspection.
crates/​server/​src/​web/​token_jwt_bearer.rs Gates JWT bearer grants.
crates/​server/​src/​web/​token_exchange/​tests/​uri_target.rs Preserves issuer bindings in target fixtures.
crates/​server/​src/​web/​token_exchange/​tests/​sender_flow.rs Awaits Redis fixture validation.
crates/​server/​src/​web/​token_exchange/​tests/​rar.rs Revalidates rebuilt token services.
crates/​server/​src/​web/​token_exchange/​tests/​projection_pool.rs Uses owned pools and administrative fault injection.
crates/​server/​src/​web/​token_exchange/​tests/​mtls_profile.rs Awaits Redis fixture validation.
crates/​server/​src/​web/​token_exchange/​tests/​lifetime.rs Validates token-lifetime fixture bindings.
crates/​server/​src/​web/​token_exchange/​tests/​legacy_request.rs Awaits Redis fixture validation.
crates/​server/​src/​web/​token_exchange/​tests/​client_scope_ceiling.rs Awaits Redis fixture validation.
crates/​server/​src/​web/​token_exchange/​tests.rs Revalidates exchange and Redis fixtures.
crates/​server/​src/​web/​token_exchange.rs Gates token-exchange grants.
crates/​server/​src/​web/​token_endpoint.rs Gates token endpoint admission.
crates/​server/​src/​web/​token_device_code/​projection_tests.rs Shares projection authorities through Arc.
crates/​server/​src/​web/​token_device_code.rs Gates device-code grants.
crates/​server/​src/​web/​token_client_credentials/​tests.rs Validates issuer and projection fixture bindings.
crates/​server/​src/​web/​token_client_credentials.rs Gates grants and extracts admission checks.
crates/​server/​src/​web/​token_authorization_code.rs Gates authorization-code exchange.
crates/​server/​src/​web/​test_support/​authorization.rs Revalidates reloaded authorization state.
crates/​server/​src/​web/​test_support.rs Creates independent runtime pools and preserves authority history.
crates/​server/​src/​web/​state.rs Restricts external state construction.
crates/​server/​src/​web/​router.rs Gates readiness on namespace validation.
crates/​server/​src/​web/​resource_endpoint/​tests.rs Tests validated runtime-pool failure.
crates/​server/​src/​web/​resource_endpoint.rs Gates resource access.
crates/​server/​src/​web/​par_endpoint.rs Gates pushed authorization requests.
crates/​server/​src/​web/​oauth_conformance_tests/​sender_contract.rs Uses database-derived UserInfo fixtures and format constraints.
crates/​server/​src/​web/​namespace_runtime/​tests.rs Tests namespace binding, refusal, and restart behavior.
crates/​server/​src/​web/​namespace_runtime/​lifecycle_tests.rs Tests factory monitoring and listener drain.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​upstream_consumption.rs Checks callback-state preservation.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​token_consumption.rs Checks code and refresh-token preservation.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​support.rs Provides validated acceptance fixtures.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​recovery_consumption.rs Checks recovery-token and CSRF preservation.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_upstream.rs Exercises successful upstream authorization and refresh.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_upstream_supplier.rs Supplies observable OAuth and JWKS responses.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_upstream_observation.rs Checks links, sessions, and refresh-token rotation.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_upstream_fixture.rs Seeds upstream configuration and registration.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_support.rs Provides positive-flow request helpers.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_jwt_bearer.rs Exercises signed assertions and replay refusal.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_dcr.rs Checks usable dynamic registrations.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​positive_application.rs Checks current and revoked authorization grants.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​management_fixture.rs Supplies management identities and sessions.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​management_effects.rs Checks namespace-scoped session mutations.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​login_consumption.rs Checks login effects and CSRF preservation.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​exceptions.rs Checks unchanged endpoint admission exceptions.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​device_consumption.rs Checks device approval and grant preservation.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​browser_consumption.rs Checks browser sessions and logout relays.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​authorization_fixture.rs Supplies signed authorization fixtures.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests/​authorization_consumption.rs Checks PAR, JAR, and consent preservation.
crates/​server/​src/​web/​namespace_runtime/​acceptance_tests.rs Registers namespace acceptance suites.
crates/​server/​src/​web/​mod.rs Registers namespace runtime support.
crates/​server/​src/​web/​management/​users/​store/​profile_update.rs Maps ownership errors during updates.
crates/​server/​src/​web/​management/​user_support/​store/​invitation.rs Maps ownership errors during invitations.
crates/​server/​src/​web/​management/​user_support/​errors.rs Defines nondisclosing ownership error responses.
crates/​server/​src/​web/​management/​user_support/​audit.rs Explicitly casts runtime-command status parameters.
crates/​server/​src/​web/​management/​user_support.rs Exports ownership error mapping.
crates/​server/​src/​web/​management/​user_inventory/​sessions/​workflows/​revoke.rs Requires the target namespace for revocation.
crates/​server/​src/​web/​management/​user_inventory/​sessions/​workflows/​oidc.rs Requires a namespace capability for logout dispatch.
crates/​server/​src/​web/​management/​user_inventory/​sessions/​workflows/​invalidate.rs Requires the target namespace for invalidation.
crates/​server/​src/​web/​management/​tests/​policy_and_runtime/​subject_format.rs Checks ownership atomicity and predecessor inventory.
crates/​server/​src/​web/​management/​tests/​policy_and_runtime/​runtime_keys/​runtime_key_pg/​fixtures.rs Retains permanent authority until database teardown.
crates/​server/​src/​web/​management/​tests/​policy_and_runtime/​configuration_membership/​credentials.rs Separates administrative fault injection from runtime operations.
crates/​server/​src/​web/​management/​tests/​policy_and_runtime/​application_revocation.rs Checks rejection of deleted-subject reassignment.
crates/​server/​src/​web/​management/​tests/​policy_and_runtime/​application_identity_reuse.rs Checks permanent ownership and rename-back behavior.
crates/​server/​src/​web/​management/​tests/​policy_and_runtime/​application_dcr_lock.rs Uses administrative trigger setup and cleanup.
crates/​server/​src/​web/​management/​tests/​initialization/​fingerprints.rs Separates schema setup from restricted runtime reads.
crates/​server/​src/​web/​management/​tests/​initialization/​exchange_reload/​isolation.rs Awaits Redis fixture validation.
crates/​server/​src/​web/​management/​tests/​initialization/​exchange_reload.rs Revalidates reloaded exchange services.
crates/​server/​src/​web/​management/​tests/​initialization.rs Uses owned databases and restricted runtime identities.
crates/​server/​src/​web/​management/​tests/​bootstrap_and_profiles/​common_and_runtime.rs Initializes the namespace permit field.
crates/​server/​src/​web/​logout_endpoint.rs Gates logout and relay consumption.
crates/​server/​src/​web/​logout_dispatch.rs Requires namespace-bound logout publication.
crates/​server/​src/​web/​local_auth/​post.rs Gates local login submission.
crates/​server/​src/​web/​local_auth/​logout.rs Gates local logout.
crates/​server/​src/​web/​local_auth/​get.rs Gates login-form issuance.
crates/​server/​src/​web/​local_auth_recovery.rs Gates activation and password recovery.
crates/​server/​src/​web/​device_flow/​verification/​user_code.rs Gates device verification.
crates/​server/​src/​web/​device_flow/​verification/​actions.rs Gates device approval and denial.
crates/​server/​src/​web/​device_flow/​authorization.rs Gates device authorization.
crates/​server/​src/​web/​dcr_registration.rs Gates dynamic registration creation.
crates/​server/​src/​web/​dcr_configuration/​update.rs Gates registration updates.
crates/​server/​src/​web/​dcr_configuration/​read.rs Gates registration reads.
crates/​server/​src/​web/​dcr_configuration/​delete.rs Gates registration deletion.
crates/​server/​src/​web/​authorize_endpoint/​consent/​submission.rs Gates consent submission.
crates/​server/​src/​web/​authorize_endpoint.rs Gates authorization admission.
crates/​server/​src/​web/​authorization_consent_tests/​request_objects.rs Revalidates shared protocol stores.
crates/​server/​src/​web/​authorization_consent_tests/​repetition.rs Revalidates rebuilt issuance services.
crates/​server/​src/​web/​authorization_consent_tests.rs Updates pool-failure and authority fixtures.
crates/​server/​src/​web/​application_authorization.rs Gates authorization-context publication.
crates/​server/​src/​subject_ownership/​history/​pre_migration.rs Collects locked predecessor-schema history.
crates/​server/​src/​subject_ownership/​history/​digest.rs Implements framed hashing and metadata serialization.
crates/​server/​src/​subject_ownership/​history.rs Exposes history validation and hashing modules.
crates/​server/​src/​subject_ownership.rs Defines the ownership module and assurance boundary.
crates/​server/​src/​main/​upstream_runtime.rs Switches bootstrap imports to crate-local modules.
crates/​server/​src/​main/​token_runtime.rs Updates token bootstrap imports.
crates/​server/​src/​main/​tests/​key_managers.rs Updates runtime-key test imports.
crates/​server/​src/​main/​tests/​env_inventory.rs Tracks the relocated bootstrap source.
crates/​server/​src/​main/​sync_runtime.rs Updates runtime synchronization imports.
crates/​server/​src/​main/​runtime_key_managers.rs Updates key-manager bootstrap imports.
crates/​server/​src/​main/​runtime_config.rs Updates runtime-configuration imports.
crates/​server/​src/​main/​protocol_runtime.rs Updates protocol-store bootstrap imports.
crates/​server/​src/​main/​oidc_runtime.rs Updates OIDC bootstrap imports.
crates/​server/​src/​main/​federation_runtime.rs Updates federation bootstrap imports.
crates/​server/​src/​main/​dpop.rs Updates DPoP bootstrap imports.
crates/​server/​src/​main/​device_runtime.rs Updates device-store bootstrap imports.
crates/​server/​src/​main/​dcr_runtime.rs Updates registration bootstrap imports.
crates/​server/​src/​main/​client_runtime.rs Updates client bootstrap imports.
crates/​server/​src/​main/​browser_auth_runtime.rs Updates browser-store bootstrap imports.
crates/​server/​src/​main/​background_tasks/​runtime_config/​monitor.rs Updates runtime-monitor imports.
crates/​server/​src/​main/​background_tasks/​runtime_config.rs Updates monitor setup imports.
crates/​server/​src/​main/​background_tasks/​cleanup.rs Updates cleanup imports and references.
crates/​server/​src/​main/​background_tasks.rs Updates supervised-task imports.
crates/​server/​src/​main/​app_state.rs Validates namespace ownership during state construction.
crates/​server/​src/​lib.rs Exposes runtime construction and ownership modules.
crates/​server/​src/​federation/​tests/​pg_repositories.rs Preserves permanent namespace parents during cleanup.
crates/​server/​src/​db_schema_revision_tests.rs Uses explicit administrative test connections.
crates/​server/​src/​bin/​aegaeon-subject-ownership.rs Adds the history CLI entry point.
crates/​server/​src/​authcode/​token/​validator.rs Exposes internal issuer-binding validation.
crates/​server/​src/​authcode/​token/​runtime.rs Exposes internal issuance issuer checks.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +99 to +100
pub async fn shutdown_requested(&self) {
self.runtime_restart.notified().await;
Comment on lines +111 to +115
match self.subject_namespace.as_deref() {
Some(permit) if environment == self.environment_id && permit.matches(self) => {
Ok(NamespaceCapability {
_permit: permit,
state: self,
Comment on lines +438 to +443
FOR relation_row IN SELECT c.oid, c.relname, c.relowner FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE (n.nspname = 'aegaeon' AND c.relname IN ('environments', 'end_users',
'subject_ownership_namespaces', 'subject_ownership_adoptions',
'end_user_identity_owners', 'end_user_subject_reservations'))
OR (c.relname='atlas_schema_revisions' AND n.nspname IN ('public','aegaeon')) LOOP
Comment thread crates/server/src/subject_ownership/history/pre_migration.rs Outdated
Base automatically changed from fix/oidc-subject-format to main October 2, 2026 16:04
Copilot AI balanced review requested due to automatic review settings October 2, 2026 16:09
) -> TestResult {
let (state, env) = fixture().await?;
let (id, subject) = user(&state, &env).await?;
let password = "namespace-test-password";
pub(super) async fn human_session(state: &AppState, env: &TestEnvironment) -> TestResult<String> {
let admin = Uuid::new_v4();
let email = format!("namespace-{admin}@example.com");
let password = "namespace-fixture-password";

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Fix the wrong-database privilege test, pending-namespace status error mapping, and excessive runtime access to adoption receipts.

Review effort: Balanced
Findings: 5 High severity

Open (5)
Resolved since last review (1)

std::env::set_var("AEGAEON_RUNTIME_ISSUER_HOST", &environment.issuer_host);
sqlx::query("INSERT INTO aegaeon.control_plane_policies (id) VALUES ('default') ON CONFLICT (id) DO NOTHING")
.execute(&pool).await?;
let admin = sqlx::PgPool::connect(&std::env::var("AEGAEON_TEST_ADMIN_DATABASE_URL")?).await?;
GRANT USAGE ON SCHEMA aegaeon TO aegaeon_subject_owner, aegaeon_subject_maintenance;
END IF;
IF pg_catalog.to_regclass('aegaeon.subject_ownership_namespaces') IS NOT NULL THEN
EXECUTE pg_catalog.format('GRANT SELECT ON aegaeon.subject_ownership_namespaces, aegaeon.subject_ownership_adoptions TO %I', runtime_name);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation security Security policy, reporting channels and hardening spec Compliance matrix, registers and schemas

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants