Core: calternal-auth (passkeys, OIDC, sessions, invites, recovery, first admin) #3

Closed
opened 2026-09-24 07:05:40 +00:00 by kayg · 14 comments
Owner

Codex job auth. Task brief lives with the orchestrator; the job comments progress here.

Base: 5f15b1e66a

Codex job `auth`. Task brief lives with the orchestrator; the job comments progress here. Base: 5f15b1e66ac9f1e781add30ed77a2594dda4472e
Author
Owner

Starting job/auth at base 5f15b1e66a. The worktree has no auth crate yet. I will implement only crates/calternal-auth/**, verify the requested standalone gates, and commit on job/auth.

Starting job/auth at base 5f15b1e66ac9f1e781add30ed77a2594dda4472e. The worktree has no auth crate yet. I will implement only crates/calternal-auth/**, verify the requested standalone gates, and commit on job/auth.
Author
Owner

Finding: webauthn-rs 0.5 passkey registration leaves resident-key selection optional by default, while discoverable login requires resident credentials. The registration API will explicitly request a resident key and tests must cover usernameless login. SQLx 0.9 migration macro also requires the macros feature in the standalone crate.

Finding: webauthn-rs 0.5 passkey registration leaves resident-key selection optional by default, while discoverable login requires resident credentials. The registration API will explicitly request a resident key and tests must cover usernameless login. SQLx 0.9 migration macro also requires the macros feature in the standalone crate.
Author
Owner

Finding: webauthn-authenticator-rs 0.5.5 SoftPasskey rejects resident-key requests, so its cryptographic end-to-end test simulates credential discovery and the user handle while the production challenge explicitly requires a resident key. The mock OIDC issuer tests reject bad nonce, audience, and expiry, then verifies a token after JWKS rotation.

Finding: webauthn-authenticator-rs 0.5.5 SoftPasskey rejects resident-key requests, so its cryptographic end-to-end test simulates credential discovery and the user handle while the production challenge explicitly requires a resident key. The mock OIDC issuer tests reject bad nonce, audience, and expiry, then verifies a token after JWKS rotation.
Author
Owner

Finished job/auth on branch job/auth at 37c304186a.

Built: standalone calternal-auth library with SQLite migrations and AuthStore, passkey setup/login/add/remove, OIDC discovery and code+PKCE flow, hashed cookie/bearer sessions, invites, recovery, re-enrolment, security events, Axum routes, and an OpenAPI fragment. Only crates/calternal-auth/** was committed. Cargo.lock was not committed. cargo clean removed build output.

Gates (verbatim output):

CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 cargo fmt --manifest-path crates/calternal-auth/Cargo.toml --check (exit 0):

CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 cargo clippy --manifest-path crates/calternal-auth/Cargo.toml --all-targets -- -D warnings (exit 0):

    Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.33s

CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 cargo test --manifest-path crates/calternal-auth/Cargo.toml (exit 0):

   Compiling calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 9.64s
     Running unittests src/lib.rs (crates/calternal-auth/target/debug/deps/calternal_auth-062e9e517318d47c)

running 13 tests
test api::tests::extractor_keeps_cookie_and_bearer_session_kinds_separate ... ok
test api::tests::rate_limit_isolated_by_peer_ip ... ok
test store::tests::sessions_are_kind_bound_and_revocable ... ok
test store::tests::admin_reenrol_link_is_single_use ... ok
test store::tests::oidc_cannot_claim_first_user_or_owner_role ... ok
test store::tests::profile_role_and_disable_changes_take_effect ... ok
test store::tests::username_is_case_insensitive_and_invite_single_use ... ok
test store::tests::setup_is_single_use_under_concurrency ... ok
test store::tests::sessions_expire_at_idle_and_absolute_deadlines ... ok
test passkey::tests::setup_registration_then_usernameless_login ... ok
test store::tests::recovery_code_is_one_time ... ok
test oidc::tests::groups_claim_maps_admin_and_guest ... ok
test oidc::tests::validates_nonce_audience_expiry_and_refreshes_rotated_key ... ok

test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.46s

   Doc-tests calternal_auth

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Known gaps: webauthn-authenticator-rs SoftPasskey cannot create resident credentials, so the signed WebAuthn test simulates browser discovery and userHandle; a hardware or platform authenticator test is still needed. The server must serve apple-app-site-association for Apple passkey sharing and supply Axum ConnectInfo for per-peer rate buckets (otherwise one fallback bucket is used). Integration into a server binary and generated cross-client contracts are outside this worktree.

Implementation decisions to confirm: setup token rotates on each process startup until an owner exists, while logging once per AuthState; only an owner can change roles and the owner cannot be disabled or demoted; custom hashed session storage was used instead of tower-sessions so only session ID hashes are persisted.

Finished job/auth on branch job/auth at 37c304186a76d230e2ffcf7a98acd8260ba8c0f9. Built: standalone calternal-auth library with SQLite migrations and AuthStore, passkey setup/login/add/remove, OIDC discovery and code+PKCE flow, hashed cookie/bearer sessions, invites, recovery, re-enrolment, security events, Axum routes, and an OpenAPI fragment. Only crates/calternal-auth/** was committed. Cargo.lock was not committed. cargo clean removed build output. Gates (verbatim output): `CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 cargo fmt --manifest-path crates/calternal-auth/Cargo.toml --check` (exit 0): ``` ``` `CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 cargo clippy --manifest-path crates/calternal-auth/Cargo.toml --all-targets -- -D warnings` (exit 0): ``` Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth) Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.33s ``` `CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 cargo test --manifest-path crates/calternal-auth/Cargo.toml` (exit 0): ``` Compiling calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth) Finished `test` profile [unoptimized + debuginfo] target(s) in 9.64s Running unittests src/lib.rs (crates/calternal-auth/target/debug/deps/calternal_auth-062e9e517318d47c) running 13 tests test api::tests::extractor_keeps_cookie_and_bearer_session_kinds_separate ... ok test api::tests::rate_limit_isolated_by_peer_ip ... ok test store::tests::sessions_are_kind_bound_and_revocable ... ok test store::tests::admin_reenrol_link_is_single_use ... ok test store::tests::oidc_cannot_claim_first_user_or_owner_role ... ok test store::tests::profile_role_and_disable_changes_take_effect ... ok test store::tests::username_is_case_insensitive_and_invite_single_use ... ok test store::tests::setup_is_single_use_under_concurrency ... ok test store::tests::sessions_expire_at_idle_and_absolute_deadlines ... ok test passkey::tests::setup_registration_then_usernameless_login ... ok test store::tests::recovery_code_is_one_time ... ok test oidc::tests::groups_claim_maps_admin_and_guest ... ok test oidc::tests::validates_nonce_audience_expiry_and_refreshes_rotated_key ... ok test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.46s Doc-tests calternal_auth running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Known gaps: webauthn-authenticator-rs SoftPasskey cannot create resident credentials, so the signed WebAuthn test simulates browser discovery and userHandle; a hardware or platform authenticator test is still needed. The server must serve apple-app-site-association for Apple passkey sharing and supply Axum ConnectInfo for per-peer rate buckets (otherwise one fallback bucket is used). Integration into a server binary and generated cross-client contracts are outside this worktree. Implementation decisions to confirm: setup token rotates on each process startup until an owner exists, while logging once per AuthState; only an owner can change roles and the owner cannot be disabled or demoted; custom hashed session storage was used instead of tower-sessions so only session ID hashes are persisted.
Author
Owner

Starting independent read-only defensive audit on branch job/auth at base/head 37c304186a76d230e2ffcf7a98acd8260ba8c0f9. I will review the §7/§14 contract, inspect auth paths, run focused crate gates/probes outside the worktree, and append concrete findings to the external findings file.

Starting independent read-only defensive audit on branch `job/auth` at base/head `37c304186a76d230e2ffcf7a98acd8260ba8c0f9`. I will review the §7/§14 contract, inspect auth paths, run focused crate gates/probes outside the worktree, and append concrete findings to the external findings file.
Author
Owner

calternal-auth independent audit — 2026-09-24, head 37c304186a

  • Critical — unscoped installation tokens can become durable account authority. crates/calternal-auth/src/api.rs:139-171,509-552,605-638,654-667 accepts any installation bearer token as CurrentUser for every route; crates/calternal-auth/migrations/0001_auth.sql:25-35 has no scope column. Concrete sequence: prompt injection in an agent container reads its pre-authenticated installation token; it calls POST /auth/passkeys/add/start, registers an attacker-held passkey via unauthenticated /auth/passkeys/registration/finish, then authenticates even after the installation token is revoked. With an owner's token it can also change roles and issue re-enrolment links. Fix: encode server-side session scopes and installation type, issue agent-container tokens restricted to required data API operations and the user's allowed Home/Group resources, deny auth/account/security-admin routes to them, and require a fresh passkey assertion for credential/link/role/security changes.
  • High — all clients behind Traefik share one rate-limit bucket. crates/calternal-auth/src/api.rs:303-317 keys only ConnectInfo<SocketAddr> peer IP, which is always Traefik; :103-115 permits 120 total auth requests per minute per bucket. Concrete sequence: one remote client sends 121 POST /auth/passkeys/login/start requests; a second user through Traefik then gets 429 on all /auth/* requests for the remainder of that window. Fix: use a trusted-proxy-only client-IP extraction policy at the server edge with explicit proxy CIDRs and sanitized forwarded chain, plus separate per-identity and endpoint budgets; never trust arbitrary forwarded headers from direct clients.
  • Medium — anonymous recovery start reveals valid usernames. crates/calternal-auth/src/api.rs:357-379 looks up username before checking code; crates/calternal-auth/src/passkey.rs:88-137 issues a challenge for any supplied code. Concrete sequence: submit {"username":"alice","code":"garbage"} and {"username":"unknown","code":"garbage"} to /auth/passkeys/recovery/start; the first receives a challenge and the second receives 401. Fix: validate recovery proof before returning a challenge or make both responses indistinguishable in status, shape and timing, with per-user recovery attempt budgets.
# calternal-auth independent audit — 2026-09-24, head 37c304186a76d230e2ffcf7a98acd8260ba8c0f9 - **Critical — unscoped installation tokens can become durable account authority.** `crates/calternal-auth/src/api.rs:139-171,509-552,605-638,654-667` accepts any installation bearer token as `CurrentUser` for every route; `crates/calternal-auth/migrations/0001_auth.sql:25-35` has no scope column. Concrete sequence: prompt injection in an agent container reads its pre-authenticated installation token; it calls `POST /auth/passkeys/add/start`, registers an attacker-held passkey via unauthenticated `/auth/passkeys/registration/finish`, then authenticates even after the installation token is revoked. With an owner's token it can also change roles and issue re-enrolment links. Fix: encode server-side session scopes and installation type, issue agent-container tokens restricted to required data API operations and the user's allowed Home/Group resources, deny auth/account/security-admin routes to them, and require a fresh passkey assertion for credential/link/role/security changes. - **High — all clients behind Traefik share one rate-limit bucket.** `crates/calternal-auth/src/api.rs:303-317` keys only `ConnectInfo<SocketAddr>` peer IP, which is always Traefik; `:103-115` permits 120 total auth requests per minute per bucket. Concrete sequence: one remote client sends 121 `POST /auth/passkeys/login/start` requests; a second user through Traefik then gets 429 on all `/auth/*` requests for the remainder of that window. Fix: use a trusted-proxy-only client-IP extraction policy at the server edge with explicit proxy CIDRs and sanitized forwarded chain, plus separate per-identity and endpoint budgets; never trust arbitrary forwarded headers from direct clients. - **Medium — anonymous recovery start reveals valid usernames.** `crates/calternal-auth/src/api.rs:357-379` looks up username before checking code; `crates/calternal-auth/src/passkey.rs:88-137` issues a challenge for any supplied code. Concrete sequence: submit `{"username":"alice","code":"garbage"}` and `{"username":"unknown","code":"garbage"}` to `/auth/passkeys/recovery/start`; the first receives a challenge and the second receives 401. Fix: validate recovery proof before returning a challenge or make both responses indistinguishable in status, shape and timing, with per-user recovery attempt budgets.
Author
Owner

Further findings recorded in the external audit file:

  • OIDC group mappings apply only at just-in-time creation: after calternal-admins is removed, an existing linked User remains admin (oidc.rs:169-175,176-193).
  • An Existing passkey registration flow survives revocation of the session that started it (api.rs:509-524,425-441; passkey.rs:202-207,257-265).
  • Role changes preserve existing session tokens, so a copied member token gains admin authority on promotion (store.rs:330-351,597-627).
  • Several authority updates commit before their security_events insert, so a failed audit write leaves the change without an event (store.rs:339-350, among others).

Concrete request sequences and fixes are appended to findings.md outside the worktree.

Further findings recorded in the external audit file: - OIDC group mappings apply only at just-in-time creation: after `calternal-admins` is removed, an existing linked User remains admin (`oidc.rs:169-175,176-193`). - An Existing passkey registration flow survives revocation of the session that started it (`api.rs:509-524,425-441`; `passkey.rs:202-207,257-265`). - Role changes preserve existing session tokens, so a copied member token gains admin authority on promotion (`store.rs:330-351,597-627`). - Several authority updates commit before their `security_events` insert, so a failed audit write leaves the change without an event (`store.rs:339-350`, among others). Concrete request sequences and fixes are appended to `findings.md` outside the worktree.
Author
Owner

Independent read-only audit finished on branch job/auth, head 37c304186a76d230e2ffcf7a98acd8260ba8c0f9. No worktree changes or commit. Full ranked findings, request sequences, locations and recommended fixes: /home/kayg/.local/state/codex-jobs/calternal/auth-review/findings.md.

Main findings: unscoped installation tokens can reach passkey/admin routes; Traefik puts all clients into one rate-limit bucket; OIDC group removal does not demote an existing admin; pending passkey addition survives session revocation; role promotion preserves copied tokens; authority changes and security events are not atomic; recovery-start reveals usernames; revoke-all and a real resident-credential test are missing. tower-sessions is absent despite the design decision. No username/email/subject-collision takeover found: OIDC identities are keyed by issuer+subject, email is unused, and username collision causes creation failure rather than linking.

Gate output (verbatim terminal excerpts):

cargo fmt --manifest-path crates/calternal-auth/Cargo.toml --check: exit 0, no output.

cargo clippy --manifest-path crates/calternal-auth/Cargo.toml --all-targets -- -D warnings:

    Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 35.35s

cargo test --manifest-path crates/calternal-auth/Cargo.toml:

test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 25.11s

   Doc-tests calternal_auth

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

All cargo commands used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, and the external CARGO_TARGET_DIR. cargo clean output:

     Removed 4438 files, 1.6GiB total

The generated untracked Cargo.lock was removed, and git status --short is empty.

Independent read-only audit finished on branch `job/auth`, head `37c304186a76d230e2ffcf7a98acd8260ba8c0f9`. No worktree changes or commit. Full ranked findings, request sequences, locations and recommended fixes: `/home/kayg/.local/state/codex-jobs/calternal/auth-review/findings.md`. Main findings: unscoped installation tokens can reach passkey/admin routes; Traefik puts all clients into one rate-limit bucket; OIDC group removal does not demote an existing admin; pending passkey addition survives session revocation; role promotion preserves copied tokens; authority changes and security events are not atomic; recovery-start reveals usernames; revoke-all and a real resident-credential test are missing. `tower-sessions` is absent despite the design decision. No username/email/subject-collision takeover found: OIDC identities are keyed by issuer+subject, email is unused, and username collision causes creation failure rather than linking. Gate output (verbatim terminal excerpts): `cargo fmt --manifest-path crates/calternal-auth/Cargo.toml --check`: exit 0, no output. `cargo clippy --manifest-path crates/calternal-auth/Cargo.toml --all-targets -- -D warnings`: ``` Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth) Finished `dev` profile [unoptimized + debuginfo] target(s) in 35.35s ``` `cargo test --manifest-path crates/calternal-auth/Cargo.toml`: ``` test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 25.11s Doc-tests calternal_auth running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` All cargo commands used `CARGO_PROFILE_DEV_DEBUG=line-tables-only`, `CARGO_INCREMENTAL=0`, and the external `CARGO_TARGET_DIR`. `cargo clean` output: ``` Removed 4438 files, 1.6GiB total ``` The generated untracked Cargo.lock was removed, and `git status --short` is empty.
Author
Owner

Starting audit fixes on branch job/auth at base 37c304186a. Read CLAUDE.md, CONTEXT.md, both design versions, and the complete auth audit. Work is limited to crates/calternal-auth/**; I will add regression tests for each fix and run the standalone crate gates.

Starting audit fixes on branch job/auth at base 37c304186a76d230e2ffcf7a98acd8260ba8c0f9. Read CLAUDE.md, CONTEXT.md, both design versions, and the complete auth audit. Work is limited to crates/calternal-auth/**; I will add regression tests for each fix and run the standalone crate gates.
Author
Owner

Findings confirmed in code: sessions has no scope or installation type column; CurrentUser accepts every valid bearer session on authority routes; Existing passkey registration stores only user ID; the OIDC existing-identity return precedes group parsing; several store methods write before a separate security event insert. Regression tests will encode these pre-fix failures.

Findings confirmed in code: sessions has no scope or installation type column; CurrentUser accepts every valid bearer session on authority routes; Existing passkey registration stores only user ID; the OIDC existing-identity return precedes group parsing; several store methods write before a separate security event insert. Regression tests will encode these pre-fix failures.
Author
Owner

Implemented server-persisted session scopes and typed HomeAndShared resource scope; added agent-token issuance (data only, 24 h), fresh assertion state, session-bound passkey registration, transactional role/disable revocation, OIDC role reconciliation, and trusted-proxy client-IP parsing. Dependency source confirms SoftPasskey rejects resident-key creation at softpasskey.rs:200, so its existing assertion test cannot prove actual discovery. I am adding focused regression tests and running crate gates now.

Implemented server-persisted session scopes and typed HomeAndShared resource scope; added agent-token issuance (data only, 24 h), fresh assertion state, session-bound passkey registration, transactional role/disable revocation, OIDC role reconciliation, and trusted-proxy client-IP parsing. Dependency source confirms SoftPasskey rejects resident-key creation at softpasskey.rs:200, so its existing assertion test cannot prove actual discovery. I am adding focused regression tests and running crate gates now.
Author
Owner

Regression tests now cover the pre-fix exploit paths: an agent token on account routes, forwarded-chain spoofing, stale OIDC admin membership, passkey completion after initiating-session revocation, live-token privilege gain, event-insert failure leaving a role changed, recovery proof lookup, and bulk revocation. Each test would fail against the audited implementation (or cannot compile there because the required API did not exist). SoftPasskey cannot create a resident credential, so that test is now explicitly named simulated usernameless login; actual browser/CTAP discovery remains a stated gap.

Regression tests now cover the pre-fix exploit paths: an agent token on account routes, forwarded-chain spoofing, stale OIDC admin membership, passkey completion after initiating-session revocation, live-token privilege gain, event-insert failure leaving a role changed, recovery proof lookup, and bulk revocation. Each test would fail against the audited implementation (or cannot compile there because the required API did not exist). SoftPasskey cannot create a resident credential, so that test is now explicitly named simulated usernameless login; actual browser/CTAP discovery remains a stated gap.
Author
Owner

Finished on branch job/auth at head 2120ac3ec4. Built scoped, hash-only sessions; 24 h renewable data-only agent tokens with a typed HomeAndShared resource limit; fresh same-session passkey/OIDC assertions; passkey flow binding; trusted-proxy client IP and separate rate budgets; OIDC role reconciliation; transactional authority events and session revocation; recovery proof checking; and revoke-all. 29 tests pass. Every regression test represents a behavior that failed in the audited code (or required a missing API). No issue was closed. cargo clean removed 1.6 GiB of build output.

Known gaps: actual resident-credential usernameless selection cannot be tested with webauthn-authenticator-rs SoftPasskey 0.5.5, which rejects resident-key creation. Its test explicitly simulates browser selection. The files layer must enforce the typed resource scope; that layer is outside this worktree's owned files. No live Traefik/browser integration was run.

Decisions beyond the design wording: migration revokes all unclassified pre-scope sessions and requires login; agent renewal rotates the token; per-minute budgets are login 30/IP and 10/User, recovery 10/IP and 5/username plus 5/User, invite 20/IP and 10/username plus 10/token. OIDC login counts as fresh only for a User without passkeys. Initial signup still issues recovery codes as part of credential enrollment.

Gate output verbatim:

cargo fmt --manifest-path crates/calternal-auth/Cargo.toml --check (exit 0, no output):

cargo clippy --manifest-path crates/calternal-auth/Cargo.toml --all-targets -- -D warnings (exit 0):

    Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5.95s

cargo test --manifest-path crates/calternal-auth/Cargo.toml (exit 0):

    Blocking waiting for file lock on package cache
    Blocking waiting for file lock on package cache
    Blocking waiting for file lock on package cache
    Blocking waiting for file lock on package cache
   Compiling calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 26.95s
     Running unittests src/lib.rs (crates/calternal-auth/target/debug/deps/calternal_auth-a3b704cbfb9f39fb)

running 29 tests
test api::tests::forwarded_chain_uses_first_untrusted_hop_from_right ... ok
test oidc::tests::groups_authoritative_defaults_to_true_in_provider_config ... ok
test api::tests::agent_token_cannot_extract_account_authority ... ok
test api::tests::rate_limit_isolated_by_peer_ip ... ok
test api::tests::authority_routes_require_recent_assertion_on_same_session ... ok
test api::tests::extractor_keeps_cookie_and_bearer_session_kinds_separate ... ok
test store::tests::admin_reenrol_link_is_single_use ... ok
test store::tests::agent_token_has_data_scope_and_home_shares_limit ... ok
test store::tests::human_session_scopes_follow_role ... ok
test store::tests::migration_revokes_unclassified_pre_scope_sessions ... ok
test store::tests::oidc_cannot_claim_first_user_or_owner_role ... ok
test store::tests::oidc_reconcile_downgrades_and_preserves_owner ... ok
test store::tests::profile_role_and_disable_changes_take_effect ... ok
test oidc::tests::oidc_reauth_marks_only_initiating_session ... ok
test oidc::tests::existing_identity_reconciles_groups_by_default ... ok
test store::tests::revoke_all_keeps_only_current_and_requires_fresh_for_changes ... ok
test store::tests::role_and_disable_revoke_sessions_and_event_failure_rolls_back ... ok
test store::tests::sessions_are_kind_bound_and_revocable ... ok
test passkey::tests::existing_registration_fails_after_initiating_session_revoked ... ok
test store::tests::setup_is_single_use_under_concurrency ... ok
test store::tests::unlink_oidc_keeps_a_credential_and_rolls_back_on_audit_failure ... ok
test store::tests::username_is_case_insensitive_and_invite_single_use ... ok
test store::tests::sessions_expire_at_idle_and_absolute_deadlines ... ok
test passkey::tests::setup_registration_then_simulated_usernameless_login ... ok
test oidc::tests::groups_claim_maps_admin_and_guest ... ok
test store::tests::recovery_code_is_one_time ... ok
test store::tests::recovery_proof_is_checked_before_challenge ... ok
test oidc::tests::non_authoritative_groups_only_set_initial_role ... ok
test oidc::tests::validates_nonce_audience_expiry_and_refreshes_rotated_key ... ok

test result: ok. 29 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 41.92s

   Doc-tests calternal_auth

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Finished on branch job/auth at head 2120ac3ec40111f18929e31b78c4b34d5371ecf5. Built scoped, hash-only sessions; 24 h renewable data-only agent tokens with a typed HomeAndShared resource limit; fresh same-session passkey/OIDC assertions; passkey flow binding; trusted-proxy client IP and separate rate budgets; OIDC role reconciliation; transactional authority events and session revocation; recovery proof checking; and revoke-all. 29 tests pass. Every regression test represents a behavior that failed in the audited code (or required a missing API). No issue was closed. `cargo clean` removed 1.6 GiB of build output. Known gaps: actual resident-credential usernameless selection cannot be tested with webauthn-authenticator-rs SoftPasskey 0.5.5, which rejects resident-key creation. Its test explicitly simulates browser selection. The files layer must enforce the typed resource scope; that layer is outside this worktree's owned files. No live Traefik/browser integration was run. Decisions beyond the design wording: migration revokes all unclassified pre-scope sessions and requires login; agent renewal rotates the token; per-minute budgets are login 30/IP and 10/User, recovery 10/IP and 5/username plus 5/User, invite 20/IP and 10/username plus 10/token. OIDC login counts as fresh only for a User without passkeys. Initial signup still issues recovery codes as part of credential enrollment. Gate output verbatim: `cargo fmt --manifest-path crates/calternal-auth/Cargo.toml --check` (exit 0, no output): ``` ``` `cargo clippy --manifest-path crates/calternal-auth/Cargo.toml --all-targets -- -D warnings` (exit 0): ``` Checking calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth) Finished `dev` profile [unoptimized + debuginfo] target(s) in 5.95s ``` `cargo test --manifest-path crates/calternal-auth/Cargo.toml` (exit 0): ``` Blocking waiting for file lock on package cache Blocking waiting for file lock on package cache Blocking waiting for file lock on package cache Blocking waiting for file lock on package cache Compiling calternal-auth v0.1.0 (/home/kayg/Developer/calternal-wt/auth/crates/calternal-auth) Finished `test` profile [unoptimized + debuginfo] target(s) in 26.95s Running unittests src/lib.rs (crates/calternal-auth/target/debug/deps/calternal_auth-a3b704cbfb9f39fb) running 29 tests test api::tests::forwarded_chain_uses_first_untrusted_hop_from_right ... ok test oidc::tests::groups_authoritative_defaults_to_true_in_provider_config ... ok test api::tests::agent_token_cannot_extract_account_authority ... ok test api::tests::rate_limit_isolated_by_peer_ip ... ok test api::tests::authority_routes_require_recent_assertion_on_same_session ... ok test api::tests::extractor_keeps_cookie_and_bearer_session_kinds_separate ... ok test store::tests::admin_reenrol_link_is_single_use ... ok test store::tests::agent_token_has_data_scope_and_home_shares_limit ... ok test store::tests::human_session_scopes_follow_role ... ok test store::tests::migration_revokes_unclassified_pre_scope_sessions ... ok test store::tests::oidc_cannot_claim_first_user_or_owner_role ... ok test store::tests::oidc_reconcile_downgrades_and_preserves_owner ... ok test store::tests::profile_role_and_disable_changes_take_effect ... ok test oidc::tests::oidc_reauth_marks_only_initiating_session ... ok test oidc::tests::existing_identity_reconciles_groups_by_default ... ok test store::tests::revoke_all_keeps_only_current_and_requires_fresh_for_changes ... ok test store::tests::role_and_disable_revoke_sessions_and_event_failure_rolls_back ... ok test store::tests::sessions_are_kind_bound_and_revocable ... ok test passkey::tests::existing_registration_fails_after_initiating_session_revoked ... ok test store::tests::setup_is_single_use_under_concurrency ... ok test store::tests::unlink_oidc_keeps_a_credential_and_rolls_back_on_audit_failure ... ok test store::tests::username_is_case_insensitive_and_invite_single_use ... ok test store::tests::sessions_expire_at_idle_and_absolute_deadlines ... ok test passkey::tests::setup_registration_then_simulated_usernameless_login ... ok test oidc::tests::groups_claim_maps_admin_and_guest ... ok test store::tests::recovery_code_is_one_time ... ok test store::tests::recovery_proof_is_checked_before_challenge ... ok test oidc::tests::non_authoritative_groups_only_set_initial_role ... ok test oidc::tests::validates_nonce_audience_expiry_and_refreshes_rotated_key ... ok test result: ok. 29 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 41.92s Doc-tests calternal_auth running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ```
Author
Owner

Completed on dev in d0f24396ec (Merge job/auth: calternal-auth with audit hardening (#3)).

Completed on dev in d0f24396eca026efd63dc663a6ff2278006afc5e (Merge job/auth: calternal-auth with audit hardening (#3)).
kayg closed this issue 2026-10-01 05:08:19 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#3
No description provided.