Repository navigation
ctutils v0.4.4 - #1569
Merged
Merged
ctutils v0.4.4#1569
Conversation
This was referenced Oct 23, 2026
tarcieri
added a commit
to RustCrypto/crypto-bigint
that referenced
this pull request
Oct 23, 2026
This release includes important security fixes: RustCrypto/utils#1569
djc
pushed a commit
to rustsec/advisory-db
that referenced
this pull request
Oct 23, 2026
This advisory covers issues fixed in v0.4.4: RustCrypto/utils#1569
2 of 13 tasks
5 tasks done
thomaseizinger
added a commit
to firezone/firezone
that referenced
this pull request
Oct 23, 2026
Versions of `ctutils` before 0.4.4 can generate branches in the mask generation of `Choice` on common platforms, and in its `u128` comparisons on 32-bit targets, so they are not constant-time. This is a new advisory that fails `cargo deny` on every PR. Related: RustCrypto/utils#1569
This was referenced Oct 23, 2026
CueCrux-Myles
pushed a commit
to CueCrux/Crux
that referenced
this pull request
Oct 23, 2026
ctutils < 0.4.4 has non-constant-time mask generation and u128 comparisons (RustCrypto/utils#1569). It reaches the tree through p256/ecdsa/hmac and turns Cargo deny red on every branch. Lockfile-only; ctutils 0.4.5 needs Rust 1.87, inside the current MSRV. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011G8hmqqwypRjci676mqZ6Z
CueCrux-Myles
pushed a commit
to CueCrux/Crux
that referenced
this pull request
Oct 23, 2026
ctutils < 0.4.4 has non-constant-time mask generation and u128 comparisons (RustCrypto/utils#1569). It reaches the tree through p256/ecdsa/hmac and turns Cargo deny red on every branch. Lockfile-only; ctutils 0.4.5 needs Rust 1.87, inside the current MSRV. The same bump rides #834, so whichever lands first carries it to main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011G8hmqqwypRjci676mqZ6Z
kunwarshivam
pushed a commit
to kunwarshivam/mandate
that referenced
this pull request
Oct 23, 2026
`cargo deny --locked check` fails on main. In ctutils 0.4.2, the constant-time `Choice` mask lacked an optimization barrier (RUSTSEC-2026-0385, RustCrypto/utils#1569); 0.4.4 and later fix it. ctutils is a transitive RustCrypto crate, reached through aes-gcm, crypto-bigint, digest, sec1 and universal-hash (webpush, p256, sqlx-postgres). `cargo update -p ctutils` makes a patch-level bump. Nothing else in Cargo.lock moves, and no manifest or dependency row changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU
5 of 6 tasks
kunwarshivam
added a commit
to kunwarshivam/mandate
that referenced
this pull request
Oct 23, 2026
…s for RUSTSEC-2026-0385 (DEC-2334, DEC-2338) (#2322) * CI (lane GO): run api-release in a full-checks-3 job of its own (DEC-2334, DEC-2338) #2289 added `api-release` to `cargo xtask ci full` (DEC-2338 item 5) after #2195 had split `full`'s parts into `full-checks` and `full-checks-2` (DEC-2334). No CI job ran `api-release`, and `the_full_jobs_run_exactly_the_full_group` failed on main. Its release build of `mandate-api-server` takes about five minutes on its own. Neither existing job has room for that under ten minutes (DEC-464): `full-checks-2`'s `reference` alone is about 4.5 minutes, before its two release builds. So it runs in `full-checks-3`, on the same selection, and `full` needs all three. The verdict table now shows a failed, cancelled or skipped `full-checks-3` failing `full`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU * Supply chain: bump ctutils 0.4.2 -> 0.4.5 for RUSTSEC-2026-0385 `cargo deny --locked check` fails on main. In ctutils 0.4.2, the constant-time `Choice` mask lacked an optimization barrier (RUSTSEC-2026-0385, RustCrypto/utils#1569); 0.4.4 and later fix it. ctutils is a transitive RustCrypto crate, reached through aes-gcm, crypto-bigint, digest, sec1 and universal-hash (webpush, p256, sqlx-postgres). `cargo update -p ctutils` makes a patch-level bump. Nothing else in Cargo.lock moves, and no manifest or dependency row changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU --------- Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 23, 2026
6 tasks done
mmqz
pushed a commit
to mmqz/smart-downloader
that referenced
this pull request
Oct 23, 2026
cargo-deny CI 拦截:ctutils 0.4.2 非恒时掩码生成与 u128 比较漏洞 (RUSTSEC-2026-0385,RustCrypto/utils#1569)。修复版 >=0.4.4。 与 tomjiu#162 代码变更无关——新披露 advisory,main 同样受影响; 纯 lockfile 升级,94 个依赖不变。
This was referenced Oct 23, 2026
rodalladea
added a commit
to rodalladea/bloc
that referenced
this pull request
Oct 23, 2026
## Change CI repeatedly compiles the dependency auditor and builds separate images for distribution and capacity testing. Cache the pinned auditor, advance Rust caches per revision, and persist architecture-specific BuildKit layers with a separate Rust dependency layer. Distribution smoke-tests and measures capacity on the same retained image digest, building each native platform once. Documentation-only changes skip compilation and database fixtures. Distribution-only changes retain source/policy checks without starting database fixtures; runtime, templates, assets, charts, shared fixtures and unknown paths retain full validation. Failed path selection retains validation. Update the existing transitive `ctutils` dependency from 0.4.3 to 0.4.4 to address [RUSTSEC-2026-0385](RustCrypto/utils#1569). The patch fixes constant-time mask generation and 128-bit comparisons. Other dependency versions remain unchanged. ## Behavior and decisions [CI behavior record](docs/behaviors/ci-efficiency.md): `ci-efficiency-01` through `ci-efficiency-03`. Maintainer-approved scope retains Debian slim, PostgreSQL 17/18 and native amd64/arm64 validation. Workflow policy tests inspect parsed YAML structure rather than exact indentation or mapping order. Documentation describes reproducible checks rather than individual execution logs. ## Verification - Passed Rust formatting, Clippy with warnings denied, ordinary tests and documentation with warnings denied, including after the ctutils update. - Passed `cargo audit` against the updated advisory database with the corrected lockfile. - Passed all 44 Python CI/runner/distribution policy tests, including failure propagation. - Passed actionlint 1.7.12 and `git diff --check`. - Built the real native ARM64 image and passed container checks C1–C6 for the Dockerfile change. - Confirmed a source-only change reuses the dependency build layer and recompiles only bloc. - Confirmed reordered/reformatted workflow YAML is accepted, while weakened selection gates or missing ARM64 coverage are rejected. Hosted checks passed on commit `4440481`: [CI, including PostgreSQL 17/18](https://github.com/rodalladea/bloc/actions/runs/39952917865), [dependency audit](https://github.com/rodalladea/bloc/actions/runs/39952917971), and PR title validation. Full hosted distribution, paired native capacity measurements, cluster validation and cache hit rates remain to be verified. No hosted elapsed-time improvement is claimed yet. ## Impact No database migrations, capacity-limit changes or publication-permission changes. PostgreSQL 17/18 and both native architectures remain covered. Includes a transitive Rust security patch and a changelog entry. Adds pinned `PyYAML==6.0.3` only for workflow policy tests, with safe loading and documented installation; no new application or runtime-image dependency is added. ## Checklist - [x] PR title follows Conventional Commits. - [x] Changes are scoped and contain no secrets or real identity data. - [x] Relevant tests, documentation and security changelog are updated. - [x] Changed CI behavior has agreed examples and test mappings; the dependency patch preserves application behavior. - [x] Implemented capabilities are distinguished from pending hosted verification. - [x] Existing publication permission boundaries and failure gates are preserved; the dependency security advisory is linked.
devdaviddr
added a commit
to syntropyai-hq/syntropy
that referenced
this pull request
Oct 23, 2026
Hosted `lint` fails at the `advisories` step on every open PR, in both lanes, because of **RUSTSEC-2026-0385** (https://rustsec.org/advisories/RUSTSEC-2026-0385). It affects `ctutils` 0.4.3, which comes in through `iroh` 1.4.1, a dev-dependency of `syntropy-net`; the full tree is in the output below. The advisory's fix is `>=0.4.4`. This PR runs `cargo update -p ctutils --precise 0.4.5`, the latest 0.4.x, which unblocks `lint` on all open PRs. Dependency policy: ADR-0018 §3, RFC-0062 §11.2. No new crate and no new direct dependency, so the new-dependency approval rule does not apply. `.github/CODEOWNERS` has no pattern that covers `Cargo.lock`, so this PR needs no code-owner approval. ### Lock diff (only `ctutils` changes) ```diff diff --git a/Cargo.lock b/Cargo.lock index 255b97b..c452bfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -691,9 +691,9 @@ dependencies = [ [[package]] name = "ctutils" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574" +checksum = "38d28fb6aa7dd680b3ffd1a3e64e115c177bdba63c0ae7f9cd48129ff05c4fa0" dependencies = [ "cmov", ] ``` ### `cargo xtask deny --advisories` before (origin/main) ``` deny --advisories: cargo-deny 0.20.2, advisories, with /Users/admin/syntropy/.claude/worktrees/fix-ctutils/deny.toml on /Users/admin/syntropy/.claude/worktrees/fix-ctutils/Cargo.toml error[vulnerability]: Non-constant-time mask generation and `u128` comparisons ┌─ /Users/admin/syntropy/.claude/worktrees/fix-ctutils/Cargo.lock:70:1 │ 70 │ ctutils 0.4.3 registry+https://github.com/rust-lang/crates.io-index │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected │ ├ ID: RUSTSEC-2026-0385 ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0385 ├ ## Summary automatically in CI using `cargo checkct`. ├ Announcement: RustCrypto/utils#1569 ├ Solution: Upgrade to >=0.4.4 (try `cargo update -p ctutils`) ├ ctutils v0.4.3 └── iroh v1.4.1 └── (dev) syntropy-net v0.0.0 ├── syntropy-api v0.0.0 ├── syntropy-cluster v0.0.0 └── syntropy-testkit v0.0.0 ├── (dev) syntropy-exec v0.0.0 ├── (dev) syntropy-io v0.0.0 │ ├── syntropy-exec v0.0.0 (*) │ ├── syntropy-kernels-cpu v0.0.0 │ │ └── (dev) syntropy-exec v0.0.0 (*) │ ├── syntropy-probe v0.0.0 │ └── syntropy-tier v0.0.0 ├── (dev) syntropy-kernels-cpu v0.0.0 (*) ├── (dev) syntropy-manifest v0.0.0 │ └── syntropy-graph v0.0.0 │ └── syntropy-testkit v0.0.0 (*) ├── (dev) syntropy-net v0.0.0 (*) └── (dev) syntropy-spsc v0.0.0 ├── syntropy-exec v0.0.0 (*) ├── syntropy-io v0.0.0 (*) ├── syntropy-ipc v0.0.0 ├── syntropy-kernels-cpu v0.0.0 (*) └── syntropy-net v0.0.0 (*) advisories FAILED deny --advisories: FAIL: advisories: cargo-deny exit status: 1 ``` ### `cargo xtask deny --advisories` after ``` deny --advisories: cargo-deny 0.20.2, advisories, with /Users/admin/syntropy/.claude/worktrees/fix-ctutils/deny.toml on /Users/admin/syntropy/.claude/worktrees/fix-ctutils/Cargo.toml advisories ok deny --advisories: PASS: advisories (ADR-0018 §3, RFC-0062 §11.2) ``` ### Checks (macOS host, aarch64-apple-darwin, Rust 1.99.1, cargo-deny 0.20.2) **Passed** - `cargo update -p ctutils --precise 0.4.5`: `Updating ctutils v0.4.3 -> v0.4.5`. The lock diff above changes only `ctutils`. - `cargo xtask deny --advisories`: before FAIL (RUSTSEC-2026-0385), after `PASS: advisories`. - `cargo xtask deny`: `bans ok, licenses ok, sources ok`, `PASS`. - `cargo xtask ci dep-diff --base <origin/main worktree> --head <this worktree>`: `no new direct dependency or vendored component`, `registry: no new crate to look up`, `PASS (dep-diff, registry)`. - `cargo build --workspace --locked`: finished. - `cargo test -p syntropy-net --locked`: 15 suites ok, 319 passed, 0 failed, 1 ignored. **Failed** - None. **Not run** - `cargo xtask ci lint` (full), which hosted CI runs. - D5 naming check: this machine has no banned-terms list configured. Only `Cargo.lock` changes. Signed-off-by: devdaviddr <devdaviddr@gmail.com>
4 tasks done
kunwarshivam
added a commit
to kunwarshivam/mandate
that referenced
this pull request
Oct 23, 2026
…EC-2350 S4c follow-up) (#2311) * Test the env-name pin, the vault CA mount and the exchange's launch on the deploy-manager's pods Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Pin each managed container's environment, mount the vault's CA, and launch the exchange with its vault flags Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Cite DEC-2332 for the env pin, the vault CA and the exchange's launch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Bind the API to the vault with its AppRole and the vault's CA, copied owner-only, where its binding is on (DEC-2338) api.vaultBinding projects the vault-approle-api Secret's two keys and the vault-ca CA into one read-only source directory, which an init container copies into a memory-backed directory at 0600 as api.role-id, api.secret-id and ca.crt, since mandate_vault's reader refuses any group or other bit; the API mounts it read-only and names it in MANDATE_API_VAULT_DIR, beside MANDATE_API_VAULT_ADDRESS, and its egress names the vault on 8200. Off by default; staging's values turn it on, production, which runs no vault, may not. Infrastructure design 3.1's API row says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Check that the API's AppRole is named by the api alone, its egress exactly, and its vault address exactly (DEC-2338) Every workload's volumes, environment, arguments and init containers are scanned for the AppRole's Secret, which only the api's projection may name. The api's whole egress is its unbound rules with the one vault rule added, and the vault rule is exactly its workspace's vault pod on 8200. Seeded: the AppRole mounted into each other process, an ipBlock or namespaceSelector on the vault rule, a wide peer on 443, a portless rule, and a foreign vault address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Check that only the copy and the api mount the api pod's vault volumes (DEC-2338) With the binding on, vault-sources is mounted by the vault-credentials init container alone, read-only, and vault by it read-write and by the api read-only; with it off, neither anywhere. Seeded with a copy of the api container, hardened as it is, mounting either volume as a container or an init container. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Add the role provisioner's connection-role records and start an exchange only once its roles exist (journal v0.77, DEC-2350) Journal spec §9.33 adds ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream at schema version 1, with rule 261 (a system actor and a cause) and stream rules 262 and 263 (each record tied to its OAuth request; a removal after the roles were made, each role once, on its occasion, and the executor's role on a revocation only once no generation of its executor is left running). §9.21 starts a token exchange only once its request's ConnectionRolesMade is read. Connections spec §5.2 step 4 orders the roles first. The reference module connection_roles builds the vectors: 36 invalid and 4 valid drafts, 19 rule-262 and rule-263 streams, 4 validator, 8 stream and 7 vector mutants caught. Reserves and fills DEC-2350; adds the provisioner's backlog row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Name only the added delete as DEC-2350's: the provisioner's + on its role paths is DEC-2630 item 7's Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Never remove the executor's role: the provisioner removes the token exchange's alone (DEC-2350 item 3) Rule 263 narrows to one removal per made roles, of the token exchange's role, on a closed request or a revocation. A kill switch's start after a revocation can always log in; the cost, one executor role per closed or revoked connection granting a read of its own destroyed token, is recorded in DEC-2350 with the sweep left in the backlog. The executor's role is an invalid draft; its stream cases and the process fold go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Tie each role removal to its own request's close, refresh the fixture, and grant delete on the exchange's mount alone (DEC-2350, review) Rule 263 now holds a removal's causation_id to a closer of its connection journaled after the latest ConnectionRolesMade, so it never cites an earlier request's refusal under a new request of the same id (DEC-699). The fold and the oracle each read it their own way; four new streams and a vector mutant pin it. DEC-2350 item 5 adds delete on the token exchange's mount's block only, so the policy itself keeps the executor's role. fixtures/refcases/journal.json is regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Drop read from both provisioner role blocks, and send pinned list parameters as strings (DEC-2350 item 5, V2's live check) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * E21-33: the role provisioner's identity and AppRole, delete on the exchange's roles alone, tests pending (DEC-2350) S2 of DEC-2350, the vault side, option (B): the executor's role is never removed. - Identity::Provisioner, provisioned with an AppRole and a secret id only when provisioning is given the workspace's namespace (KubernetesAuth::namespace, from --secrets-namespace); its policy is provisioner_policy for that namespace and nothing else. - provisioner_policy grants delete on the token exchange's mount's block alone (stubbed seam: provisioner_capabilities). - role_request sends the pinned list parameters, the namespace and the policy, as plain strings: OpenBao's allowed_parameters pin refuses a JSON array however it is filled, so every role request was refused (verified on OpenBao 2.7.1; stubbed seam: pinned). - A pin test that the provisioner's + sits on exactly the two Kubernetes mounts' role paths, and a live test that the provisioner's own token makes both roles, is refused a widened role, an executor role's removal, a policy and a secret, and removes the exchange's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's identity and AppRole, delete on the exchange's roles alone (DEC-2350) S2's implementation: provisioner_capabilities grants delete on the token exchange's roles alone, and pinned sends a pinned list parameter as a plain string. Deletes the pending markers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the provisioner's role blocks grant no read (DEC-2350 item 5) DEC-2350 item 5 now drops read from both blocks, since OpenBao refuses a role read under required_parameters however it is granted: the executor's block is create and update, the token exchange's create, update and delete. The pin test asserts that, and the live test that the provisioner reads neither role it makes. Merges #2278's head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's journal records and rules 261 to 263, tests pending (DEC-2350) S3 of DEC-2350: journal spec v0.77 §9.33's ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream, against the vectors' connection_roles section. Pending: the catalogue entry, each base and valid draft parsing, every invalid draft refused at its path, append judging rule 261 alone, and the verifier's fold verify_connection_roles answering every stream case of rules 262 and 263. The fold is stubbed; the parse tests fail on the unknown event type, with behaviour-only rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's journal records and rules 261 to 263 (DEC-2350) S3's implementation: the journal registers ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream at schema version 1, catalogued with no configuration, and append checks rule 261 on each (a system actor, then a cause). The verifier's fold verify_connection_roles judges rules 262 and 263 as the reference does: an answer names its own version-2 OAuth request, once; a removal follows its connection's latest roles made, once, and names a closer of those roles of its own occasion, a connect refusal or a revocation journaled after them. Deletes the pending markers and the four behaviour-only rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the policy provisioning writes for the provisioner's role is pinned without a server, test pending (DEC-2350) Review item on S2: only a live server told provisioner_policy from openbao_policy for the provisioner's role, so the gate missed a mutant there. provisioned_policy, stubbed here, is the one choice provision makes, and a unit test pins it: provisioner_policy for the provisioner given the namespace, openbao_policy for every other identity and for the provisioner without one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the policy provisioning writes for the provisioner's role is pinned without a server (DEC-2350) provision writes each role's policy through provisioned_policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner makes a connection's roles and removes the exchange's, tests pending (DEC-2350) S4a of DEC-2350: RoleProvisioner, the role provisioner's session with the vault, as OpenBaoSource is when it logs in as the provisioner: make_roles makes the executor's and then the token exchange's role as role_request forms them, and remove_exchange_role removes the exchange's. No operation removes an executor's role (DEC-2350 item 3). RoleRefusal names a failure in ConnectionRolesRefused's two reasons. Both operations and the error mapping are stubbed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner makes a connection's roles and removes the exchange's (DEC-2350) S4a's implementation: make_roles POSTs the executor's and then the token exchange's role_request, and remove_exchange_role DELETEs the exchange's, a 404 being a role already gone. A refusal maps to vault_unavailable for an outage or a sealed vault and to role_refused for every other. Removes the temporary Unimplemented variant and the pending markers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: a removal names a connect refusal of its own occasion, test pending (DEC-2350) Mutants found two readings of rule 263 the vectors leave open: a ConnectionRefused of another occasion taken for a request's close, and a removal whose occasion does not name its closer's kind. A pending test edits the removed_on_close case into each and expects rule 263 at the removal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: a removal names a connect refusal of its own occasion (DEC-2350) The fold compares a removal's named occasion against its closer's kind in one step, an occasion that names neither standing for no closer, and deletes the pending marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's plan and pass, tests pending (DEC-2350) S4b of DEC-2350: mandate-provisioner, the role provisioner's library. plan folds the control stream into the steps owed: roles to make for each unanswered version-2 OAuth request, and the exchange's role to remove once a request whose roles were made closes, or its connection is revoked. Provisioner::tick performs each on the vault within the 30 s deadline and journals it, with the opaque alert connection_roles_refused (RB-12) on a refusal. The records' drafts are real, with event ids derived from the step; the plan and the pass are stubbed. Pending: a request's roles once, a refusal and a slow vault, a close and a revocation removing only the exchange's role, a step the journal missed done again and recorded once, two racing writers, an unopened stream, and the plan against every valid vector stream. The crate is at layer 9, above mandate-vault, with its layers row and CODEOWNERS line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's plan and pass (DEC-2350) S4b's implementation. plan folds the control stream as the journal's verify_connection_roles reads rules 262 and 263: a version-2 OAuth request with no answer is owed its roles, unless it closed first, and a connection whose roles were made is owed the exchange's removal once its request closes or it is revoked, with that first closer as cause. tick performs the first step owed on the vault within the deadline, journals it, and reads the stream again, so each record is drafted against the stream as it is; another writer's record under it is read again at most APPEND_TRIES times. A refusal raises connection_roles_refused (RB-12) with no ids; a removal the vault does not do is retried by the next pass. No step removes an executor's role. Deletes the temporary Unimplemented variants and the pending markers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the live suite's vault set-up names the provisioning error it fails on Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the plan's own connection, version and occasion readings, tests pending; the feature map's entry (DEC-2350) Mutants found readings of the plan the vectors leave open: an API-key or version-1 request, a close of one connection's request before its answer, two connections' made roles, and a refusal of another occasion. Three pending tests pin each over synthetic streams. The role provisioner's feature-map entry names its code, tests and runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: a provisioner's pass ends after the steps it owed (DEC-2350) A pass takes at most the steps it first owed and APPEND_TRIES more, so a stream that never shows a record committed ends the pass as a journal halt rather than looping; the plan tests' pending markers go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: only the provisioner's session makes or removes roles, test pending A session that never logged in, built for unit tests, lets the identity check be tested with no vault running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: only the provisioner's session makes or removes roles A role operation from any other session is refused role_refused before the vault is reached. The DELETE's doc now says why a missing auth mount counts as removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's process, mandate-provisionerd (DEC-2350) The provisioner over the Postgres control stream, written as mandate-deployd writes it, and the vault, logged in by AppRole as the provisioner and again every hour. A session near its token's end that no login replaced stops the process, failed, so it never calls the vault with a lapsed token. --fixture runs it over memory and a vault that keeps nothing, and a release build refuses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the fixture run is a debug build's block, not a release stub Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the workspace services' pinned list names the role provisioner Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the workspace services' pinned list names the provisioner's process Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the API's owner-only vault copy becomes the chart's shared helper, by role mandate.vaultCopy and mandate.vaultVolumes take the process's vault role; the API's render is byte-for-byte the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the workspace chart's role provisioner, its AppRole alone and no Kubernetes credential (DEC-2350) The role-provisioner process: one Deployment per workspace once its image is named, reading ctl:<api.workspace> as mandate_role_provisioner, binding roles in its own namespace, with its AppRole and the vault's CA copied owner-only by the shared vault helper, no service-account token, and egress to the journal and its vault on 8200 alone. Infrastructure design §3.1 gains its row; roles.sql, the Compose file and initdb.sh are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's image, and its process marked built (DEC-2350) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's pod holds exactly its own volumes, and no token or ConfigMap besides (DEC-2350, review G1) Its volume set is pinned by name and kind, and its projected volume to its Secret and the vault's CA, with seeds for a projected service-account token, a token in its vault sources, an extra ConfigMap, a host path, a downward API volume, and a second kind on one volume. Infrastructure design §3.1 says its writing only the three role records is its convention, not a database grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * CI (lane GO): run api-release in a full-checks-3 job of its own (DEC-2334, DEC-2338) #2289 added `api-release` to `cargo xtask ci full` (DEC-2338 item 5) after #2195 had split `full`'s parts into `full-checks` and `full-checks-2` (DEC-2334). No CI job ran `api-release`, and `the_full_jobs_run_exactly_the_full_group` failed on main. Its release build of `mandate-api-server` takes about five minutes on its own. Neither existing job has room for that under ten minutes (DEC-464): `full-checks-2`'s `reference` alone is about 4.5 minutes, before its two release builds. So it runs in `full-checks-3`, on the same selection, and `full` needs all three. The verdict table now shows a failed, cancelled or skipped `full-checks-3` failing `full`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU * Supply chain: bump ctutils 0.4.2 -> 0.4.5 for RUSTSEC-2026-0385 `cargo deny --locked check` fails on main. In ctutils 0.4.2, the constant-time `Choice` mask lacked an optimization barrier (RUSTSEC-2026-0385, RustCrypto/utils#1569); 0.4.4 and later fix it. ctutils is a transitive RustCrypto crate, reached through aes-gcm, crypto-bigint, digest, sec1 and universal-hash (webpush, p256, sqlx-postgres). `cargo update -p ctutils` makes a patch-level bump. Nothing else in Cargo.lock moves, and no manifest or dependency row changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU --------- Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 23, 2026
kunwarshivam
added a commit
to kunwarshivam/mandate
that referenced
this pull request
Oct 23, 2026
#2313) * Test the env-name pin, the vault CA mount and the exchange's launch on the deploy-manager's pods Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Pin each managed container's environment, mount the vault's CA, and launch the exchange with its vault flags Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Cite DEC-2332 for the env pin, the vault CA and the exchange's launch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Start an OAuth connect's executor on its exchange's success (journal v0.74, DEC-2335) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Name J2 PR #2200 as an ES-22 atomic exception (DEC-2335 item 6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Test the connect's executor: started on its exchange's success, stopped when its connection closes (E21-33 K2a, DEC-2336) The tests half of DEC-77's pair. Phase::Succeeded joins the orchestrator port and the fake can succeed an instance; the manager's fold and decision have no stub form, so the tests that need a success read are pending as behaviour-only rows until K2a's implementation lands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Start the connect's executor on its exchange's success and stop it when its connection closes (E21-33 K2a, DEC-2336) The implementation half of DEC-77's pair: the manager reads the request's account, journals the executor's exchanged start while the request is open and the account's executor never ran, wants it until a refusal or revocation, and names each executor stop by the last reason taken away. The pending tests' ignore lines and behaviour-only rows go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Name K2b's executor self-check dependency and the Deployment executor's account in DEC-2336's risks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Test that each executor runs as its connection's own account (E21-33 K2b, DEC-2336 items 6 to 10) The tests half of DEC-77's pair. The orchestrator port's start takes a Launch of the exchange's lifetime and the executor's connection, and its stop the connection; the driver passes none yet and the adapter ignores it, so the tests that need it are pending as behaviour-only rows. DEC-2336 gains K2b's items and the coordinator's F2 wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Run each manager-started executor as its connection's own account, and pin it at admission (E21-33 K2b, DEC-2336 items 6 to 10) The implementation half of DEC-77's pair. The manager names an executor's connection on its start and stop and asks once per account per pass; the adapter makes and deletes the executor's hex account, names it and the namespace in its environment, and reads a succeeded pod as Succeeded. The chart pins a manager-started executor to an even-length hex account its environment names, admits that account with the executor's label, and mounts the vault token only on pods the manager starts. The pending tests' ignore lines and behaviour-only rows go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Test that an executor's start and stop name the same connection, the deployment's or the connect's (E21-33 K2b, review F1) Four pending tests: a revoked connection the deployment does not name is never chosen; a restart after the connect ended names the deployment's connection, across the manager's restart; a stop names its generation's connection once nothing else does; and no executor takes another account's connection. DEC-2336 item 6 says which connection a start names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Name each executor generation's connection when its start is folded, from its deployment or its connect (E21-33 K2b, review F1) An executor's start names the connection a running agent's deployment of its account names, else its open connect's; the manager records it per generation as it folds the start, so the stop names the same account and a restarted manager names the same one. A revoked connection no deployment names is no longer chosen. The pending tests' ignore lines and rows go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Test that a kill switch reaches an executor no agent wants, once per switch (DEC-2344 items 1 and 3) Pending E21-33. A covering kill switch gives an account's executor that every agent's retirement left down exactly one start, cause kill_switch, journaled first and caused by the switch; each later covering switch one more; a generation that ends on its own is never restarted; nothing else starts it; and a switch the executor has not answered keeps the account's last retirement from stopping it. A property over random deploys, retirements, kill switches of every scope, ends, clock steps and manager restarts checks both against an oracle computed from the operations alone. Each pending test has its behaviour-only row: the manager answers, no stub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Test that a kill-switch start crash-looping before it ends raises kill_switch_unapplied (DEC-2344 item 1) Pending E21-33. A crash of the start is restarted, so one crash loses no switch; at the crash-loop bound the manager journals ProcessCrashLooped and raises the opaque operator alert kill_switch_unapplied, once, in place of crash_loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Extend the kill-switch property to crashes and the unapplied-switch alert (DEC-2344 item 1) The executor no agent wants may now crash before it ends. The oracle allows a crash's restart only before its loop and with no switch pending, requires the switch's one start when one is, never lets the manager stop a generation a switch keeps, admits a crash loop only after a kill switch's crashing start, and requires each such loop to raise kill_switch_unapplied once and every other alert never. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Read a successful end as answering only the switches committed before its start (DEC-2344, journal v0.76 §9.21) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Add the role provisioner's connection-role records and start an exchange only once its roles exist (journal v0.77, DEC-2350) Journal spec §9.33 adds ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream at schema version 1, with rule 261 (a system actor and a cause) and stream rules 262 and 263 (each record tied to its OAuth request; a removal after the roles were made, each role once, on its occasion, and the executor's role on a revocation only once no generation of its executor is left running). §9.21 starts a token exchange only once its request's ConnectionRolesMade is read. Connections spec §5.2 step 4 orders the roles first. The reference module connection_roles builds the vectors: 36 invalid and 4 valid drafts, 19 rule-262 and rule-263 streams, 4 validator, 8 stream and 7 vector mutants caught. Reserves and fills DEC-2350; adds the provisioner's backlog row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Name only the added delete as DEC-2350's: the provisioner's + on its role paths is DEC-2630 item 7's Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Never remove the executor's role: the provisioner removes the token exchange's alone (DEC-2350 item 3) Rule 263 narrows to one removal per made roles, of the token exchange's role, on a closed request or a revocation. A kill switch's start after a revocation can always log in; the cost, one executor role per closed or revoked connection granting a read of its own destroyed token, is recorded in DEC-2350 with the sweep left in the backlog. The executor's role is an invalid draft; its stream cases and the process fold go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Tie each role removal to its own request's close, refresh the fixture, and grant delete on the exchange's mount alone (DEC-2350, review) Rule 263 now holds a removal's causation_id to a closer of its connection journaled after the latest ConnectionRolesMade, so it never cites an earlier request's refusal under a new request of the same id (DEC-699). The fold and the oracle each read it their own way; four new streams and a vector mutant pin it. DEC-2350 item 5 adds delete on the token exchange's mount's block only, so the policy itself keeps the executor's role. fixtures/refcases/journal.json is regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Start an executor no agent wants once per covering kill switch, and hold it until its switches are answered (DEC-2344 items 1 and 3) The manager starts such an executor, cause kill_switch, journaled first, once for the covering switches it has not answered, as the account of the connection its last generation ran as. It never stops a generation a switch started or one a switch read while it ran is waiting on; a success ends it, a crash restarts with back-off, and a crash loop raises kill_switch_unapplied in place of crash_loop, again once from a restarted manager. The six pending retired.rs tests run, their behaviour-only rows go, and new tests cover a revoked connection, the restarted alert, a wanted executor's successful exit, and the oracle's seeded bugs. Two older tests follow DEC-2344's change. The alert has its RB-14 section and its infrastructure design §8.2 row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Drop read from both provisioner role blocks, and send pinned list parameters as strings (DEC-2350 item 5, V2's live check) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Move the implementation's new tests here as pending: a revoked connection's start, the restarted alert, the oracle's seeded bugs (DEC-2344 item 1, review) The four tests the implementation PR wrote fail on today's manager and are pending E21-33 with behaviour-only rows: the N3 revoked-connection start, the restarted manager's one re-raise, the seeded-bug harness, and manager.rs's stopped-agent test with DEC-2344's extra start. The property expects the re-raise, and properties.rs exempts an executor's unwanted start, which retired.rs's property checks more strictly. A wanted executor's restart after a success already passes, so it is a plain test. Record::CrashLooped carries the alert it raises, crash_loop for every loop today, so the harness can seed a loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Reflow RB-14's kill_switch_unapplied escalation step Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Test that a later switch after an unapplied loop starts a new run, that a held crash waits its back-off, and that a redeploy ends a kill-switch run (DEC-2344 item 1, review) Three more tests, pending E21-33 with behaviour-only rows, each failing on today's manager: a covering switch after an unapplied crash loop starts a new run that is restarted and can loop and alert again; a crashed kill-switch generation waits backoff(0) before exactly one restart; and a deployment during a kill-switch run makes its later loop an ordinary crash_loop, after a manager restart too. The property's oracle lets such a start begin a new run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Begin a new run at a kill switch's start after an unapplied loop, and merge #2257's new tests (DEC-2344 item 1, review) A kill_switch start of an executor no agent wants clears the last run's restarts, crash loop and alert, so a later covering switch after an unapplied loop is restarted after a crash, loops again, and is reported again: a second ProcessCrashLooped and a second kill_switch_unapplied. The merge takes #2257's three new tests and deletes their ignore lines and rows; a held crash's back-off and a redeploy's ordinary loop already held and are now pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Test that a deploy and retire during a kill switch's generation does not stop it (DEC-2344 item 3, review) Pending E21-33 with its behaviour-only row: the generation a covering switch started stays running through an agent's deployment and retirement on the account, and its own end is not restarted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Let the property's oracle keep a kill-switch run held through a deployment (DEC-2344 item 3, review) A deployment on the account no longer ends a held run in the oracle's view: only its own successful end does, so a crash of it is still restarted after the agent retires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Keep a kill switch's run held through a deployment and retirement, and classify its loop at the loop (DEC-2344 item 3, review) resume no longer clears held, and a kill_switch start made while the executor is wanted no longer clears it either, so an agent deployed and retired while a switch's generation runs never gets that generation stopped before it ends itself (rule 13). A stop the manager journals is only ever of a generation it does not hold, so folding it clears held, and a replay agrees. A crash loop leaves a switch unapplied only when no agent wants the executor at the loop. #2257's new test runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * E21-33: the role provisioner's journal records and rules 261 to 263, tests pending (DEC-2350) S3 of DEC-2350: journal spec v0.77 §9.33's ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream, against the vectors' connection_roles section. Pending: the catalogue entry, each base and valid draft parsing, every invalid draft refused at its path, append judging rule 261 alone, and the verifier's fold verify_connection_roles answering every stream case of rules 262 and 263. The fold is stubbed; the parse tests fail on the unknown event type, with behaviour-only rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's journal records and rules 261 to 263 (DEC-2350) S3's implementation: the journal registers ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream at schema version 1, catalogued with no configuration, and append checks rule 261 on each (a system actor, then a cause). The verifier's fold verify_connection_roles judges rules 262 and 263 as the reference does: an answer names its own version-2 OAuth request, once; a removal follows its connection's latest roles made, once, and names a closer of those roles of its own occasion, a connect refusal or a revocation journaled after them. Deletes the pending markers and the four behaviour-only rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * Test a kill switch's start during an open connect, a connect during a held run, a connect's ordinary loop, and a stop a restart must not undo (DEC-2351 item 2, review) Three pending E21-33 with rows, each failing on today's manager, and one plain test that passes today: an executor only a connect wants loops as crash_loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Hold a kill switch's run by the agents alone, and say so in the loop's alert, and merge #2257's tests (DEC-2351 item 2, review) A kill_switch start of an executor holds its run when no agent of its account is deployed and not stopped, whatever connect request wants it, and the crash loop's alert says kill_switch_unapplied when the run is held and no agent wants the executor at the loop, as journal spec rule 264 reads it; a runtime's start never holds. A deployment on a connection revoked since counts until its AgentStopped, as the rule reads it. The merge takes #2257's four new tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * E21-33: a removal names a connect refusal of its own occasion, test pending (DEC-2350) Mutants found two readings of rule 263 the vectors leave open: a ConnectionRefused of another occasion taken for a request's close, and a removal whose occasion does not name its closer's kind. A pending test edits the removed_on_close case into each and expects rule 263 at the removal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: a removal names a connect refusal of its own occasion (DEC-2350) The fold compares a removal's named occasion against its closer's kind in one step, an occasion that names neither standing for no closer, and deletes the pending marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the token exchange waits for its request's roles, tests pending (DEC-2350 S6) A connect's token exchange starts only once its request's ConnectionRolesMade is read (journal spec §9.21, §9.33). The new roles suite and the exchange property's oracle say so; the existing connect tests gain the Made row their scenarios now need. The pending tests fail on the manager's behaviour, which has no stub to stop at, and are named in xtask/behaviour-only until the implementation lands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the seeded double launch waits for a first launch to copy (DEC-2350 S6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the token exchange waits for its request's roles (DEC-2350 S6) The manager reads the role provisioner's ConnectionRolesMade and keeps each request's event id; a connect's token exchange is wanted only once the Made that answers its own request is read, so a refusal, a record for another request, or none starts nothing, and the connect ends by its deadline (journal spec §9.21). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * CI (lane GO): run api-release in a full-checks-3 job of its own (DEC-2334, DEC-2338) #2289 added `api-release` to `cargo xtask ci full` (DEC-2338 item 5) after #2195 had split `full`'s parts into `full-checks` and `full-checks-2` (DEC-2334). No CI job ran `api-release`, and `the_full_jobs_run_exactly_the_full_group` failed on main. Its release build of `mandate-api-server` takes about five minutes on its own. Neither existing job has room for that under ten minutes (DEC-464): `full-checks-2`'s `reference` alone is about 4.5 minutes, before its two release builds. So it runs in `full-checks-3`, on the same selection, and `full` needs all three. The verdict table now shows a failed, cancelled or skipped `full-checks-3` failing `full`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU * Supply chain: bump ctutils 0.4.2 -> 0.4.5 for RUSTSEC-2026-0385 `cargo deny --locked check` fails on main. In ctutils 0.4.2, the constant-time `Choice` mask lacked an optimization barrier (RUSTSEC-2026-0385, RustCrypto/utils#1569); 0.4.4 and later fix it. ctutils is a transitive RustCrypto crate, reached through aes-gcm, crypto-bigint, digest, sec1 and universal-hash (webpush, p256, sqlx-postgres). `cargo update -p ctutils` makes a patch-level bump. Nothing else in Cargo.lock moves, and no manifest or dependency row changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU --------- Co-authored-by: Claude <noreply@anthropic.com>
kunwarshivam
added a commit
to kunwarshivam/mandate
that referenced
this pull request
Oct 23, 2026
…EC-2350 S4b-2 follow-up) (#2308) * Add the role provisioner's connection-role records and start an exchange only once its roles exist (journal v0.77, DEC-2350) Journal spec §9.33 adds ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream at schema version 1, with rule 261 (a system actor and a cause) and stream rules 262 and 263 (each record tied to its OAuth request; a removal after the roles were made, each role once, on its occasion, and the executor's role on a revocation only once no generation of its executor is left running). §9.21 starts a token exchange only once its request's ConnectionRolesMade is read. Connections spec §5.2 step 4 orders the roles first. The reference module connection_roles builds the vectors: 36 invalid and 4 valid drafts, 19 rule-262 and rule-263 streams, 4 validator, 8 stream and 7 vector mutants caught. Reserves and fills DEC-2350; adds the provisioner's backlog row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Name only the added delete as DEC-2350's: the provisioner's + on its role paths is DEC-2630 item 7's Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Never remove the executor's role: the provisioner removes the token exchange's alone (DEC-2350 item 3) Rule 263 narrows to one removal per made roles, of the token exchange's role, on a closed request or a revocation. A kill switch's start after a revocation can always log in; the cost, one executor role per closed or revoked connection granting a read of its own destroyed token, is recorded in DEC-2350 with the sweep left in the backlog. The executor's role is an invalid draft; its stream cases and the process fold go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Tie each role removal to its own request's close, refresh the fixture, and grant delete on the exchange's mount alone (DEC-2350, review) Rule 263 now holds a removal's causation_id to a closer of its connection journaled after the latest ConnectionRolesMade, so it never cites an earlier request's refusal under a new request of the same id (DEC-699). The fold and the oracle each read it their own way; four new streams and a vector mutant pin it. DEC-2350 item 5 adds delete on the token exchange's mount's block only, so the policy itself keeps the executor's role. fixtures/refcases/journal.json is regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * Drop read from both provisioner role blocks, and send pinned list parameters as strings (DEC-2350 item 5, V2's live check) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LmJtE8JXVQjyqTteJ5b9Cm * E21-33: the role provisioner's identity and AppRole, delete on the exchange's roles alone, tests pending (DEC-2350) S2 of DEC-2350, the vault side, option (B): the executor's role is never removed. - Identity::Provisioner, provisioned with an AppRole and a secret id only when provisioning is given the workspace's namespace (KubernetesAuth::namespace, from --secrets-namespace); its policy is provisioner_policy for that namespace and nothing else. - provisioner_policy grants delete on the token exchange's mount's block alone (stubbed seam: provisioner_capabilities). - role_request sends the pinned list parameters, the namespace and the policy, as plain strings: OpenBao's allowed_parameters pin refuses a JSON array however it is filled, so every role request was refused (verified on OpenBao 2.7.1; stubbed seam: pinned). - A pin test that the provisioner's + sits on exactly the two Kubernetes mounts' role paths, and a live test that the provisioner's own token makes both roles, is refused a widened role, an executor role's removal, a policy and a secret, and removes the exchange's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's identity and AppRole, delete on the exchange's roles alone (DEC-2350) S2's implementation: provisioner_capabilities grants delete on the token exchange's roles alone, and pinned sends a pinned list parameter as a plain string. Deletes the pending markers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the provisioner's role blocks grant no read (DEC-2350 item 5) DEC-2350 item 5 now drops read from both blocks, since OpenBao refuses a role read under required_parameters however it is granted: the executor's block is create and update, the token exchange's create, update and delete. The pin test asserts that, and the live test that the provisioner reads neither role it makes. Merges #2278's head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's journal records and rules 261 to 263, tests pending (DEC-2350) S3 of DEC-2350: journal spec v0.77 §9.33's ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream, against the vectors' connection_roles section. Pending: the catalogue entry, each base and valid draft parsing, every invalid draft refused at its path, append judging rule 261 alone, and the verifier's fold verify_connection_roles answering every stream case of rules 262 and 263. The fold is stubbed; the parse tests fail on the unknown event type, with behaviour-only rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's journal records and rules 261 to 263 (DEC-2350) S3's implementation: the journal registers ConnectionRolesMade, ConnectionRolesRefused and ConnectionRolesRemoved on the control stream at schema version 1, catalogued with no configuration, and append checks rule 261 on each (a system actor, then a cause). The verifier's fold verify_connection_roles judges rules 262 and 263 as the reference does: an answer names its own version-2 OAuth request, once; a removal follows its connection's latest roles made, once, and names a closer of those roles of its own occasion, a connect refusal or a revocation journaled after them. Deletes the pending markers and the four behaviour-only rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the policy provisioning writes for the provisioner's role is pinned without a server, test pending (DEC-2350) Review item on S2: only a live server told provisioner_policy from openbao_policy for the provisioner's role, so the gate missed a mutant there. provisioned_policy, stubbed here, is the one choice provision makes, and a unit test pins it: provisioner_policy for the provisioner given the namespace, openbao_policy for every other identity and for the provisioner without one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the policy provisioning writes for the provisioner's role is pinned without a server (DEC-2350) provision writes each role's policy through provisioned_policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner makes a connection's roles and removes the exchange's, tests pending (DEC-2350) S4a of DEC-2350: RoleProvisioner, the role provisioner's session with the vault, as OpenBaoSource is when it logs in as the provisioner: make_roles makes the executor's and then the token exchange's role as role_request forms them, and remove_exchange_role removes the exchange's. No operation removes an executor's role (DEC-2350 item 3). RoleRefusal names a failure in ConnectionRolesRefused's two reasons. Both operations and the error mapping are stubbed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner makes a connection's roles and removes the exchange's (DEC-2350) S4a's implementation: make_roles POSTs the executor's and then the token exchange's role_request, and remove_exchange_role DELETEs the exchange's, a 404 being a role already gone. A refusal maps to vault_unavailable for an outage or a sealed vault and to role_refused for every other. Removes the temporary Unimplemented variant and the pending markers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: a removal names a connect refusal of its own occasion, test pending (DEC-2350) Mutants found two readings of rule 263 the vectors leave open: a ConnectionRefused of another occasion taken for a request's close, and a removal whose occasion does not name its closer's kind. A pending test edits the removed_on_close case into each and expects rule 263 at the removal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: a removal names a connect refusal of its own occasion (DEC-2350) The fold compares a removal's named occasion against its closer's kind in one step, an occasion that names neither standing for no closer, and deletes the pending marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's plan and pass, tests pending (DEC-2350) S4b of DEC-2350: mandate-provisioner, the role provisioner's library. plan folds the control stream into the steps owed: roles to make for each unanswered version-2 OAuth request, and the exchange's role to remove once a request whose roles were made closes, or its connection is revoked. Provisioner::tick performs each on the vault within the 30 s deadline and journals it, with the opaque alert connection_roles_refused (RB-12) on a refusal. The records' drafts are real, with event ids derived from the step; the plan and the pass are stubbed. Pending: a request's roles once, a refusal and a slow vault, a close and a revocation removing only the exchange's role, a step the journal missed done again and recorded once, two racing writers, an unopened stream, and the plan against every valid vector stream. The crate is at layer 9, above mandate-vault, with its layers row and CODEOWNERS line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's plan and pass (DEC-2350) S4b's implementation. plan folds the control stream as the journal's verify_connection_roles reads rules 262 and 263: a version-2 OAuth request with no answer is owed its roles, unless it closed first, and a connection whose roles were made is owed the exchange's removal once its request closes or it is revoked, with that first closer as cause. tick performs the first step owed on the vault within the deadline, journals it, and reads the stream again, so each record is drafted against the stream as it is; another writer's record under it is read again at most APPEND_TRIES times. A refusal raises connection_roles_refused (RB-12) with no ids; a removal the vault does not do is retried by the next pass. No step removes an executor's role. Deletes the temporary Unimplemented variants and the pending markers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the live suite's vault set-up names the provisioning error it fails on Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the plan's own connection, version and occasion readings, tests pending; the feature map's entry (DEC-2350) Mutants found readings of the plan the vectors leave open: an API-key or version-1 request, a close of one connection's request before its answer, two connections' made roles, and a refusal of another occasion. Three pending tests pin each over synthetic streams. The role provisioner's feature-map entry names its code, tests and runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: a provisioner's pass ends after the steps it owed (DEC-2350) A pass takes at most the steps it first owed and APPEND_TRIES more, so a stream that never shows a record committed ends the pass as a journal halt rather than looping; the plan tests' pending markers go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: only the provisioner's session makes or removes roles, test pending A session that never logged in, built for unit tests, lets the identity check be tested with no vault running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: only the provisioner's session makes or removes roles A role operation from any other session is refused role_refused before the vault is reached. The DELETE's doc now says why a missing auth mount counts as removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the role provisioner's process, mandate-provisionerd (DEC-2350) The provisioner over the Postgres control stream, written as mandate-deployd writes it, and the vault, logged in by AppRole as the provisioner and again every hour. A session near its token's end that no login replaced stops the process, failed, so it never calls the vault with a lapsed token. --fixture runs it over memory and a vault that keeps nothing, and a release build refuses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the fixture run is a debug build's block, not a release stub Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the workspace services' pinned list names the role provisioner Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: the workspace services' pinned list names the provisioner's process Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * E21-33: CI builds the role provisioner in release and checks it refuses its fixture cargo xtask ci provisionerd-release, in full and in check, like stub-release: it builds mandate-provisionerd with --release when the diff selects it, runs it with --fixture, and requires exit 2 with fixture_not_built alone on stderr. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF * CI (lane GO): run api-release in a full-checks-3 job of its own (DEC-2334, DEC-2338) #2289 added `api-release` to `cargo xtask ci full` (DEC-2338 item 5) after #2195 had split `full`'s parts into `full-checks` and `full-checks-2` (DEC-2334). No CI job ran `api-release`, and `the_full_jobs_run_exactly_the_full_group` failed on main. Its release build of `mandate-api-server` takes about five minutes on its own. Neither existing job has room for that under ten minutes (DEC-464): `full-checks-2`'s `reference` alone is about 4.5 minutes, before its two release builds. So it runs in `full-checks-3`, on the same selection, and `full` needs all three. The verdict table now shows a failed, cancelled or skipped `full-checks-3` failing `full`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU * Supply chain: bump ctutils 0.4.2 -> 0.4.5 for RUSTSEC-2026-0385 `cargo deny --locked check` fails on main. In ctutils 0.4.2, the constant-time `Choice` mask lacked an optimization barrier (RUSTSEC-2026-0385, RustCrypto/utils#1569); 0.4.4 and later fix it. ctutils is a transitive RustCrypto crate, reached through aes-gcm, crypto-bigint, digest, sec1 and universal-hash (webpush, p256, sqlx-postgres). `cargo update -p ctutils` makes a patch-level bump. Nothing else in Cargo.lock moves, and no manifest or dependency row changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoxcMViCbnGUTPSaduuGYU * Run the role provisioner's release check in full-checks-3 Main's full-job split has no room for it in full-checks-2, so it runs beside the API's release build, about two minutes more, under ten (DEC-464). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5V2t72QcDywyLPViJtmFF --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security
Choice::to_*_maskconstant-time codegen (#1567)u128comparisons on 32-bit targets (#1568)